askrav askrav - 2 months ago 6x
C++ Question

Delphi's LongRec() func in c++

I'm rewriting code from Delphi to C++ and here's a line I can't translate:

typedef vector<char> ByteArray;

unsigned char Bytes[4];

Buf[sCP + J] = LongRec( R ).Bytes[3 - I];

sCP, J, R and I variables are Ints.

Google says "LongRec declares a record that stores the various parts of the specified value as type Word or Byte." but I still can't understand how to make it work in C++


In C++, you would use a union, but note that getting anything else out as you put in is undefined behaviour. It will probably work the same way as in Delphi, but only on the same platform, i.e. with the same ABI as Win32 or Win64, depending on the compiler target used in Delphi.

So in Delphi:

  LongRec = packed record
    case Integer of
      0: (Lo, Hi: Word);
      1: (Words: array [0..1] of Word);
      2: (Bytes: array [0..3] of Byte);

And "literal" C++ translation:

#pragma pack(push, 1)
union LongRec
     struct { unsigned short Lo, Hi; };
     struct { unsigned short Words[2]; };
     struct { unsigned char Bytes[4]; };
#pragma pack(pop)

(The above assumes that sizeof(short) == 2, that variables are little-endian and that the structs completely overlap, all of which may not be the case for all platforms.)

But again, if you want to read the second to highest byte of a long and do something like

byte2 = reinterpret_cast<LongRec *>(&myLongint)->Bytes[2];

that is undefined behaviour (although it will probably work on the same Windows platform as Delphi).

The proper behaviour is (slower, but correct):

byte2 = myLongint >> 16 & 0xFF;


myHiWord = myLongint >> 16 & 0xFFFF;

But even that assumes that a byte is an octet, which is not always the case. In other words, this is not portable, and will only work as is on Windows 32 and 64 bit.