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]"