We need a function that will be able to return both int32 and int64. How to implement it most competently?

The goal is to bring to the function a code that receives integers of a specified size from a binary file by the specified endian.

  • If unsigned and sky "conflicts" - union. There is an option template (duality will be), there is an option implicit cast (an object is created that can cast to both int64 and int32). - nick_n_a
  • Do you need two of these values ​​at once? If so, then you can use a pair - Andrej Levkovitch
  • one
    Alternatively, return int64 in all cases, but in some cases leave the upper half of the bits unused. - HolyBlackCat
  • This is not the most competent decision. Maybe I want an int128 or 1024 - Jedi Knight
  • one
    The question is not clear. Which means "which will be able to return both int32 and int64." When is a decision made about what exactly should be returned? At compile time? At runtime? "Specified size at the specified endian" - when is all this indicated? At compile time? At runtime? - AnT 2:26 pm

2 answers 2

Option 1. I offer you an option with a template

template<typename T> T getNumData(void* buff, int offs){ T ret; for (int i=0;i<sizeof(T);i++) ((char*)&ret)[i] = ((char*)buff)[i+offs]; return ret; } 

With reverse indian it is similar but ((char*)&ret)[sizeof(T)-i-1] Perhaps this variant is crooked, I don’t know how to write with castes.

When using, you have to specify the desired type getNumData<int32>(q,0) this will allow you to immediately decode all 3-4 options from 8bit to 64.

If the getNumData converted to such a template<typename T> void getNumData(T& ret, void* data, int offs) then you don’t have to specify <int32> - you can write getNumData(retvar,q,0); The option is quite good in speed.

Still there are options:

  • To return the union (simply, but it will be a) the loss of the sign b) is impossible for the reverse indian.

  • Return int64 and cast (impossible for reverse indian)

  • Return the class, and set the caste rules for each type (more code, convenient, but you can get confused) - implicit cast.


Option 2. You can get rid of the extra <> "sacrificing" an extra class (some compilers will eat the struct , but all the operators belong to the class classes). I will show implicit cast - that's what it's called, i.e. the compiler looks to which class the caste goes, and makes a call to a specific operator. It is necessary to check this method with a disassembler so that the compiler would not create new and delete calls. For one variable, the compiler does not create constructors destructors. There may be a loss of speed during use, so it’s best to check The simplified scheme is:

 class /*struct*/ autocast { public: void *data; // кастим к int32, в комментарии вариант для обратного indian operator int32() { return *(int32*)data; /*return getData<int>(data,0)*/ } // кастим к int64 operator int64() { return *(int64*)data; } }; //И можно запилить autocast /*inline*/ getNumDataVar(void* data){ /*Дописать offs*/ autocast ret; ret.data = data; return ret; } // вызов делается так (но тип слева должен быть одним из тех, // для которого существует оператор implicit cast) int32 query = getNumDataVar(q); 

The disadvantage - instead of one call - there will be two calls (some compilers can make 4-re, but specifying inline can compile both one call and zero, depends on the compiler), but it is more convenient to use. The disadvantage is more code - for each type you will have to write a separate caste, unlike the first option, but sometimes this separation allows you to add speed (it will be easier to get rid of cycles and n p).

  • @HolyBlackCat yes, for sure. for 32 sizeof = 4, 4-3 = 1 and not 0. - nick_n_a
  • Here with the templates <type> good - Jedi Knight
  • I have been looking for a solution for a long time whether it is possible to make y = f (x) so as not to indicate <type>. It exists, and for some reason is still not described anywhere in this version. I think ... the last option will be pleasant if you get tired of writing <type>. On c # I used this in one of the projects. Stackoverflow.com/questions/797470/… . - nick_n_a
  • It should be faster to implement, so it seems better without classes for Int - Jedi Knight
  • To whom speed is important - they use the template, and in some cases, the cycles can be replaced by #define. High-speed performance is such a controversial topic ... by the way ... the second method allows you to remove cycles (with a template, removing cycles is more difficult). In addition, getNumDataVar is declared as inline - new compilers will line it up in the code - and there will be one challenge. And in the "variations" it is possible to make assembly inserts ... and the second code can then work faster than the first (for the time being, theoretically). I believe that the questioners should know the different implementation options (workers). I do not think that the answer should be divided into 2 different answers. - nick_n_a

In C ++, you cannot overload functions by the return value. In other words, the next overload is wrong.

 int32 getInt(); int64 getInt(); 

But there are other ways:

  1. Make two different functions and call the necessary:

     int32 getInt32(); int64 getInt64(); 

    You can make this function template, but it doesn’t change much.

  2. Do not return value at all. Pass an index or links to both:

     void getInt(int32&, int64&); 
  3. Return a structure from a pair of elements.

     struct UniversalInt { int32 i32; int64 i64; }; UniversalInt getInt(); 

    But there are problems: firstly, regardless of the resultant, the memory will be allocated for both elements, and one is used, and secondly, it is not known what type was returned.

  4. Use union . This will partially solve the problem of allocating extra memory. This option should not be used in such an implementation at all.

      union UniversalInt { int32 i32; int64 i64; }; UniversalInt getInt(); 
  5. To union add information about the returned type. The good news is that this structure already exists - std::variant ; the bad news is that the added std::variant was only in C ++ 17.

      std::variant<int32, int64> getInt(); 

    Alternatively, you can use boost::variant . For POD types, this structure will look pretty simple and you can write it yourself. As soon as it turns out that a suitable variant makes sense to think about using a visitor pattern.

In my opinion the best option will be the first.

  • Sample at least eliminates code duplication for n functions. - Jedi Knight