On Wed, 31 May 2006, Emil Kondayan wrote:

Can someone tell me why "ip_hl" and "ip_v" are of type "u_int" when the
structure is packed and they only fill a byte?
Because ip.h is mostly written in C (!= Gnu C) and bit-fields cannot have
type u_char in C.  From an old draft of C99 (n689.txt):

%      [#8]  A  bit-field  shall have a type that is a qualified or
%      unqualified version of _Bool, signed int, or  unsigned  int.

And my second question:do these "#define ..." directives allocate space in the
structure?
No.

struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN
u_int ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_int ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
} __packed;
__packed is a syntax error in C, and shouldn't be needed here since
struct ip is carefully hand-packed.  However, it may help due to Gnu
C's very surprising semantics for u_int bit-fields.  u_char and u_int
bit-fields affected alignment (and thus packing) as follows:

- u_char bit-fields don't affect alignment
- u_int bit-fields result in the struct containing them having the
  same alignment requirements as u_int.

E.g., the follow struct has alignment requirements 1 and thus has size 1
too:

    struct foo { unsigned char x:8; };

but the following struct has alignment requirements 4 (on i386's) and thus
is is padded at the end to size 4 (on i386's):

    struct bar { unsigned int x:8; };

I've never seen this behaviour or more details of it documented.  C only
requires packing bit-fields reasonably contiguously AFAIK.

Struct ip must have size 20, and this happens naturally on machines with
32-bit ints (which is all machines supported by FreeBSD).  On machines
with 64-bit ints, gcc would bogusly pad it to size 24 without the __packed
directive on struct ip.

Even on machines with 32-bit ints, gcc's alignment requirements give
surprising results.  Consider:

    struct baz {
            unsigned short x;
            struct ip y;
    };

This should have size 22, but without the __packed directive it would
have size 24. There would be unnamed padding before y.

Consider:

    struct boo {
            unsigned char x;
            struct ip y;
    };

This should have size 22, with unnamed padding before y to align it to
its correct alignment (2, not 4), but _with_ the __packed it has size
21 and the accesses to the shorts in y in it are misaligned.  gcc knows
how to do misaligned accesses and generates extra (slow) code to access
these shorts a byte at a time on machines with strict alignment
requirements (e.g., ia64).  However, if you pass the address of y in
struct boo to a function expecting a "struct ip *", then the requirement
for the extra code is silently lost and misaligned accesses are generated.
Misaligned accesses may also cause bugs by being non-atomic.

The -Wpacked and -Wpadded warnings should be used to inhibit bogus packing.

Bruce
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to