How to write initialization of compilation time of a 4-byte character constant that is fully portable

The code (deprecated) looks something like this.

#define MAKEID(a,b,c,d) (((UInt32)a)<<24 | ((UInt32)b)<<16 
                        | ((UInt32)c)<<8 | ((UInt32)d) )
#define ID_FORM MAKEID('F','O','R','M')
//...
struct S { 
  int id;
  int x;
  double d;
  // other stuff
};
//...
S s;
socket.read(&s, sizeof(s));  // read network data over struct
if (s.id == ID_FORM) { }

The code reads the stream of characters into the structure. It is known that Sid is a 4-character constant, such as "FORM" or "DATA" in the stream (network) order, which determines the layout of the rest of the structure. All comparisons are integers using predefined constants.

The MAKEID macro is big-endian because it places the first (character) argument in the highest byte, which is also the lowest memory address. A low-element version of the macro will look like this by placing the first (character) argument in the least significant byte, which is now the lowest memory address.

 #define MAKEID(a,b,c,d) (((UInt32)d)<<24 | ((UInt32)c)<<16 
                        | ((UInt32)b)<<8 | ((UInt32)a) )

, , .

, #ifdef. endian, . - .

, . , . , , .

- , .

. , . , , big-endian 4 , "FORM". , , endianism .

+3
3

, . 4 . , , .

unsigned int MakeId(char a, char b, char c, char d) {
  char x[4] = { a, b, c, d };
  return *(int*)x;
}
unsigned int MakeId(char a, char b, char c, char d) {
  union {
    char x[4];
    int i;
  } u = { a, b, c, d };
  return u.i;
}
unsigned int MakeId(const char* s) { return *(int*)s; }

#define MAKEID(s) = *(int*)(s);

#define FORM_ID MAKEID("Form")

Qaru .

+1

MAKEID . , .

, ++ , , , . < /" > 42 << 24 42 8 , . . , MAKEID(0x12, 0x34, 0x56, 0x78) 0x12345678, .

, (, 0x12, 0x34, 0x56, 0x78), . 0x12345678 , 0x78563412 little-endian , , 0x56781234 .
, - , (, / ), , , .

, , ( , , ), , , MAKEID, . (de-) , . , , , , , .

+7

, - , :

if (ntohl(s.id) == ID_FORM) { }

: , htonl ID_FORM:

#define ID_FORM htonl(MAKEID('F','O','R','M'))

It depends on the htonlmacro. And this is usually the case. And if so, it is usually determined with the same condition that you are trying to avoid: http://www.jbox.dk/sanos/source/include/net/inet.h.html (as an example).

So, if your system htonldoes not have a macro, the only right choice that I see is to actually stick with it #ifdef.

Keep in mind that now your ID_FORM is now in the "network entity", and not the "end endness" of the host.

0
source

All Articles