This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

#pragma pack(n) scope

Does #pragma pack(n) apply to all the structures in a source code or it has to be applied to each structure separately ?
It's not clear from the manual.
In one place it says:
"You can use #pragma pack(n) to make sure that any structures with unaligned data are packed."
In other:
"This pragma aligns members of a structure to the minimum of n"

Parents
  • Note that this is yet one other problem with raw binary transfer that doesn't have anything to do with align, padding, ... of structures.

    In your example, they have problems with bit fields. They did make sure that they consumed all 16 bits just to avoid the problem with where the compiler would place any padding. But since the bit field container was larger than one byte, different architectures would still manage to have different byte orders and hence introduce a difference in the order of the bit fields.

    So:
    1) Compiler vendors can get away with it, but no one else should really try to transfer bit field containers larger than 8 bits as raw containers between different architectures. Bit fields can work quite well internally, but they were never intended to be shared.

    2) As already noted: it's way better to write code to pack/unpack structures than to fight with manual padding, pragmas etc. Besides the padding issues, there is also the question of byte orders for different data types. And the fact that many of the classical C data types can be different size on different architectures. Today, most machines have the "standard" two-complement format for integers, allowing us simple pack/unpack for integers. But it gets worse for floating point - especially when some targets emulates floating point and then maybe don't use the ISO-standardized formats for float and double.

Reply
  • Note that this is yet one other problem with raw binary transfer that doesn't have anything to do with align, padding, ... of structures.

    In your example, they have problems with bit fields. They did make sure that they consumed all 16 bits just to avoid the problem with where the compiler would place any padding. But since the bit field container was larger than one byte, different architectures would still manage to have different byte orders and hence introduce a difference in the order of the bit fields.

    So:
    1) Compiler vendors can get away with it, but no one else should really try to transfer bit field containers larger than 8 bits as raw containers between different architectures. Bit fields can work quite well internally, but they were never intended to be shared.

    2) As already noted: it's way better to write code to pack/unpack structures than to fight with manual padding, pragmas etc. Besides the padding issues, there is also the question of byte orders for different data types. And the fact that many of the classical C data types can be different size on different architectures. Today, most machines have the "standard" two-complement format for integers, allowing us simple pack/unpack for integers. But it gets worse for floating point - especially when some targets emulates floating point and then maybe don't use the ISO-standardized formats for float and double.

Children
  • Hi Per,

    Many thanks for your reply.

    How about the below example?
    en.wikipedia.org/.../Ip_(struct)

    struct ip {
       unsigned int   ip_hl:4; /* both fields are 4 bits */
       unsigned int   ip_v:4;
       uint8_t        ip_tos;
       uint16_t       ip_len;
       uint16_t       ip_id;
       uint16_t       ip_off;
       uint8_t        ip_ttl;
       uint8_t        ip_p;
       uint16_t       ip_sum;
       struct in_addr ip_src;
       struct in_addr ip_dst;
    };
    

    I remember that, all of the protocol layers in the TCP/IP suite are defined to be big endian.

    But I just can't understand how the struct ip handles data alignment problem.

  • The protocol layer may specify big endian. And not only that - the standard does define the location of the different bits.

    For a normal PC-class program, that normally just means that an IPv4 address stored in a 32-bit integer must be processed with htonl() and ntohl() to make sure that the number ends up as the expected <n>.<n>.<n>.<n>.

    But in the end, it's up to the driver layer and the compiler/library to make sure that you get valid structure data.

    In your example, ip_hl and ip_v fits in a single byte. So if you look, everything but the 8-bit fields are already 16-bit aligned. And there are 12 bytes when you reach the two structures so they are 32-bit aligned.

    The network card sends out the data byte-by-byte. So an 8-bit field isn't a problem to send and receive on the other end. It's fields that are larger than a single byte that are problematic since the network card can send them out byte-by-byte but the meaning of the high and low bytes can be swapped. That is why the standard have defined a "network byte order" and you have functions to perform conditional byte-reversals of 16-bit and 32-bit integers. So the code calls these functions without knowing if any byte-reversal will take place or not - the runtime library will do the required work.

    But no byte swap is needed for an array of bytes - and your examples can be seen as two arrays of two bytes each.

  • It doesn't!

    When used internally - within a program - there is no data alignment problem: the compiler will consistently use the same alignment rules, so there is no problem!

    The problem is that you are trying to use this structure to represent the format of data sent externally to the program - on the communication medium. So the solution to this is simple: don't do that!

    It's been mentioned before: the process of taking the information out of the program's internal representation (with its specific padding, alignment, byte-order, data representation, etc) and turning it into the required external format for transmission on the communication medium is known as Serialisation

    en.wikipedia.org/.../Serialization

    Hans-Bernhard Broeker said,

    "serialization is not a valid rationale for packing structures"

    The reverse process - receiving data from the communication medium and formatting it into the system's own internal representation - is, naturally enough, referred to a Deserialisation

  • "It doesn't!"

    For external transmission on the communication medium, it also doesn't cover the issues of byte ording, data representation, etc,...

    So, one more time:

    "serialization is not a valid rationale for packing structures"

  • Hi Andy and Per,

    Many thanks for your helps.

    I will do some more study on this.