From 999bea31a252dae1b0709166cf3c9540bda9dbb0 Mon Sep 17 00:00:00 2001 From: Xavier Leroy Date: Fri, 17 Aug 2018 10:35:59 +0200 Subject: Issue with packed structs and sizeof, alignof, offsetof in cparser/ CompCert has two implementations of sizeof, alignof and offsetof (byte offset of a struct field): - the reference implementation, in Coq, from cfrontend/Ctypes.v - the implementation used during elaboration, in OCaml, from cparser/Cutil.ml The reference Coq implementation is used as much as possible, but sometimes during elaboration the size of a type must be computed (e.g. to compute array sizes), or the offset of a field (e.g. to evaluate __builtin_offsetof), in which case the OCaml implementation is used. This causes issues with packed structs. Currently, the cparser/Cutil.ml functions ignore the "packed" attribute on structs. Their results disagree with the "true" sizes, alignments and offsets computed by the cfrontend/Ctypes.v functions after source-to-source transformation of packed structs as done in cparser/PackedStruct.ml. For example: ``` struct __packed__(1) s { char c; short s; int i; }; assert (__builtin_offsetof(struct s, i) == 3); assert (sizeof(struct s) = sizeof(char[sizeof(struct s)])); ``` The two assertions fail. In the first assertion, __builtin_offsetof is elaborated to 4, because the packed attribute is ignored during elaboration. In the second assertion, the type `char[sizeof(struct s)]` is elaborated to `char[8]`, again because the packed attribute is ignored during elaboration, while the other `sizeof(struct s)` is computed as 7 after the source-to-source transformation of packed structs. This commit changes the cparser/Cutil.ml functions so that they take the packed attribute into account when computing sizeof, alignof, offsetof, and struct_layout. Related changes: * cparser/Cutil: add `packing_parameters` function to extract packing info from attributes * cparser/Cutil: refactor and share more code between sizeof_struct, offsetof, and struct_layout * cparser/Elab: check the alignment parameters given in packed attributes. (The check was previously done in cparser/PackedStruct.ml but now it would come too late.) * cparser/Elab: refactor the checking of alignment parameters between _Alignas, attribute((aligned)), __packed__, and attribute((packed)). * cparser/PackedStructs: simplify the code, some functionality was moved to cparser/Cutil, other to cparser/Elab * cfrontend/C2C: raise an "unsupported" error if a packed struct is defined and -fpacked-structs is not given. Before, the packed attribute would be silently ignored, but now doing so would cause inconsistencies between cfrontend/ and cparser/. * test/regression/packedstruct1.c: add tests to compare the sizes and the offsets produced by the elaborator with those obtained after elaboration. --- cfrontend/C2C.ml | 4 +- cparser/Cutil.ml | 131 ++++++++++++++++++++----------- cparser/Cutil.mli | 7 +- cparser/Elab.ml | 52 ++++++++---- cparser/PackedStructs.ml | 44 ++++------- test/regression/Results/packedstruct1-32 | 12 +++ test/regression/Results/packedstruct1-64 | 12 +++ test/regression/packedstruct1.c | 42 ++++++++-- 8 files changed, 202 insertions(+), 102 deletions(-) diff --git a/cfrontend/C2C.ml b/cfrontend/C2C.ml index ce1f2c0e..ecaffbc6 100644 --- a/cfrontend/C2C.ml +++ b/cfrontend/C2C.ml @@ -610,9 +610,11 @@ let convertField env f = (intern_string f.fld_name, convertTyp env f.fld_typ) let convertCompositedef env su id attr members = + if Cutil.find_custom_attributes ["packed";"__packed__"] attr <> [] then + unsupported "packed struct (consider adding option -fpacked-structs)"; let t = match su with | C.Struct -> - let layout = Cutil.struct_layout env members in + let layout = Cutil.struct_layout env attr members in List.iter (fun (a,b) -> Debug.set_member_offset id a b) layout; TStruct (id,attr) | C.Union -> TUnion (id,attr) in diff --git a/cparser/Cutil.ml b/cparser/Cutil.ml index 4d97823a..3e2dff36 100644 --- a/cparser/Cutil.ml +++ b/cparser/Cutil.ml @@ -267,6 +267,18 @@ let alignas_attribute al = | a :: al -> alignas_attr accu al in alignas_attr 0 al +(* Extracting struct packing parameters from a set of attributes. + Assume the parameters were checked earlier, e.g. alignments are + either 0 or powers of two. *) + +let packing_parameters al = + match find_custom_attributes ["packed";"__packed__"] al with + | [[]] -> (1, 0, false) + | [[AInt n]] -> (Int64.to_int n, 0, false) + | [[AInt n; AInt p]] -> (Int64.to_int n, Int64.to_int p, false) + | [[AInt n; AInt p; AInt q]] -> (Int64.to_int n, Int64.to_int p, q = 1L) + | _ -> (0, 0, false) + (* Type compatibility *) exception Incompat @@ -461,7 +473,10 @@ let rec alignof env t = let ci = Env.find_union env name in ci.ci_alignof | TEnum(_, _) -> Some(alignof_ikind enum_ikind) -(* Compute the natural alignment of a struct or union. *) +(* Compute the natural alignment of a struct or union. + Not done here but in composite_info_decl: taking into account + the packing parameters (max-field-alignment, min-struct-alignment) + and the alignas attributes. *) let alignof_struct_union env members = let rec align_rec al = function @@ -530,7 +545,7 @@ let rec sizeof env t = (* Compute the size of a union. It is the size is the max of the sizes of fields. - Not done here but in composite_info_decl: rounding size to alignment. *) + Not done here but in composite_info_def: rounding size to alignment. *) let sizeof_union env members = let rec sizeof_rec sz = function @@ -543,69 +558,66 @@ let sizeof_union env members = end in sizeof_rec 0 members -(* Compute the size of a struct. +(* Compute the size of a struct and the byte offset of the members. We lay out fields consecutively, inserting padding to preserve their alignment. - Not done here but in composite_info_decl: rounding size to alignment. *) -let sizeof_struct env members = - let rec sizeof_rec ofs = function + The [ma] parameter is the maximal alignment for each member. + It is used for packed structs. If [ma = 0], it is ignored. + Bitfields are taken into account for the size and offset computations + but not given an offset. + Not done here but in composite_info_def: rounding size to alignment. *) +let sizeof_layout_struct env members ma = + let align_offset ofs a = + align ofs (if ma > 0 && a > ma then ma else a) in + let rec sizeof_rec ofs accu = function | [] -> - Some ofs + Some (ofs, accu) | [ { fld_typ = TArray(_, None, _) } as m ] -> (* C99: ty[] allowed as last field *) begin match alignof env m.fld_typ with - | Some a -> Some (align ofs a) + | Some a -> + let ofs = align_offset ofs a in + Some (ofs, (m.fld_name, ofs) :: accu) | None -> None end | m :: rem as ml -> if m.fld_bitfield = None then begin match alignof env m.fld_typ, sizeof env m.fld_typ with - | Some a, Some s -> sizeof_rec (align ofs a + s) rem + | Some a, Some s -> + let ofs = align_offset ofs a in + sizeof_rec (ofs + s) ((m.fld_name, ofs) :: accu) rem | _, _ -> None end else begin let (s, a, ml') = pack_bitfields ml in - sizeof_rec (align ofs a + s) ml' + sizeof_rec (align_offset ofs a + s) accu ml' end - in sizeof_rec 0 members + in sizeof_rec 0 [] members + +let sizeof_struct env members ma = + match sizeof_layout_struct env members ma with + | None -> None + | Some(sz, offsets) -> Some sz + +(* Compute the offsets of all non-bitfield members of a struct. *) +let struct_layout env attrs members = + let (ma, _, _) = packing_parameters attrs in + match sizeof_layout_struct env members ma with + | Some(sz, offsets) -> offsets + | None -> [] (* Compute the offset of a struct member *) let offsetof env ty field = - let rec sub acc name = function - | [] -> List.rev acc - | m::rem -> if m.fld_name = name then - List.rev acc - else - sub (m::acc) name rem in match unroll env ty with - | TStruct (id,_) -> + | TStruct (id, _) -> let str = Env.find_struct env id in - let pre = sub [] field.fld_name str.ci_members in - begin match sizeof_struct env pre, alignof env field.fld_typ with - | Some s, Some a -> - align s a - | _ -> assert false end - | TUnion _ -> 0 - | _ -> assert false - -(* Simplified version to compute offsets on structs without bitfields *) -let struct_layout env members = - let rec struct_layout_rec mem ofs = function - | [] -> - mem - | [ { fld_typ = TArray(_, None, _) } as m ] -> - (* C99: ty[] allowed as last field *) - begin match alignof env m.fld_typ with - | Some a -> ( m.fld_name,align ofs a)::mem - | None -> [] + let offsets = struct_layout env str.ci_attr str.ci_members in + begin try + List.assoc field.fld_name offsets + with Not_found -> + raise (Env.Error(No_member(id.C.name, "struct", field.fld_name))) end - | m :: rem -> - match alignof env m.fld_typ, sizeof env m.fld_typ with - | Some a, Some s -> - let offset = align ofs a in - struct_layout_rec ((m.fld_name,offset)::mem) (offset + s) rem - | _, _ -> [] - in struct_layout_rec [] 0 members - + | TUnion _ -> 0 + | _ -> assert false (* Determine whether a type is incomplete *) @@ -625,12 +637,35 @@ let composite_info_decl su attr = ci_attr = attr } let composite_info_def env su attr m = + let (max_field_align, min_struct_align, swapped) = packing_parameters attr in + let attr_align = alignas_attribute attr in + let natural_align = alignof_struct_union env m in let al = - let a = alignas_attribute attr in - if a > 0 then Some a else alignof_struct_union env m - and sz = + (* alignas takes precedence over packing *) + if attr_align > 0 then Some attr_align + (* ignore packing on unions for compatibility with earlier versions *) + else if su = Union then natural_align + else begin + match natural_align with + | None -> None + | Some a -> + (* If max_field_align is given, reduce natural alignment a + to be at most max_field_align *) + let a = + if max_field_align > 0 && a > max_field_align + then max_field_align + else a in + (* If min_struct_align is given, increase alignment a + to be at least min_struct_align *) + let a = + if min_struct_align > 0 && a < min_struct_align + then min_struct_align + else a in + Some a + end in + let sz = match su with - | Struct -> sizeof_struct env m + | Struct -> sizeof_struct env m max_field_align | Union -> sizeof_union env m in { ci_kind = su; ci_members = m; diff --git a/cparser/Cutil.mli b/cparser/Cutil.mli index fb875b0d..5ae5dcd7 100644 --- a/cparser/Cutil.mli +++ b/cparser/Cutil.mli @@ -36,6 +36,11 @@ val incl_attributes : attributes -> attributes -> bool val alignas_attribute : attributes -> int (* Extract the value of the [_Alignas] attributes, if any. Return 0 if none, a (positive) power of two alignment if some. *) +val packing_parameters : attributes -> int * int * bool + (* Extract the value of the [__packed__] attributes, if any. + Return a triple + (maximum field alignment, minimum struct alignment, byte swapping). + Alignments of 0 mean default alignment. *) val find_custom_attributes : string list -> attributes -> attr_arg list list (* Extract arguments of custom [Attr] attributes whose names appear in the given list of names. *) @@ -127,7 +132,7 @@ val composite_info_decl: val composite_info_def: Env.t -> struct_or_union -> attributes -> field list -> Env.composite_info val struct_layout: - Env.t -> field list -> (string * int) list + Env.t -> attributes -> field list -> (string * int) list val offsetof: Env.t -> typ -> field -> int (* Compute the offset of a struct member *) diff --git a/cparser/Elab.ml b/cparser/Elab.ml index 173d3e03..5f785c04 100644 --- a/cparser/Elab.ml +++ b/cparser/Elab.ml @@ -495,36 +495,54 @@ let elab_gcc_attr loc env = function let is_power_of_two n = n > 0L && Int64.logand n (Int64.pred n) = 0L -let extract_alignas loc a = +(* Check alignment parameter *) +let check_alignment loc n = + if not (is_power_of_two n || n = 0L) then begin + error loc "requested alignment %Ld is not a power of 2" n; false + end else + if n <> Int64.of_int (Int64.to_int n) then begin + error loc "requested alignment %Ld is too large" n; false + end else + true + +(* Process GCC attributes that have special significance. Currently we + have two: "aligned" and "packed". *) +let enter_gcc_attr loc a = match a with | Attr(("aligned"|"__aligned__"), args) -> begin match args with - | [AInt n] when is_power_of_two n || n = 0L -> AAlignas (Int64.to_int n) - | [AInt n] -> error loc "requested alignment is not a power of 2"; a - | [_] -> error loc "requested alignment is not an integer constant"; a - | [] -> a (* Use the default alignment as the gcc does *) - | _ -> error loc "'aligned' attribute takes no more than 1 argument"; a + | [AInt n] -> + if check_alignment loc n then [AAlignas (Int64.to_int n)] else [] + | [_] -> error loc "requested alignment is not an integer constant"; [] + | [] -> [] (* Use default alignment, like gcc does *) + | _ -> error loc "'aligned' attribute takes no more than 1 argument"; [] end - | _ -> a + | Attr(("packed"|"__packed__"), args) -> + begin match args with + | [] -> [a] + | [AInt n] -> if check_alignment loc n then [a] else [] + | [AInt n; AInt p] -> + if check_alignment loc n && check_alignment loc p then [a] else [] + | [AInt n; AInt p; AInt q] -> + if check_alignment loc n && check_alignment loc p then [a] else [] + | _ -> error loc "ill-formed 'packed' attribute"; [] + end + | _ -> [a] let elab_attribute env = function | GCC_ATTR (l, loc) -> List.fold_left add_attributes [] - (List.map (fun attr -> [attr]) - (List.map (extract_alignas loc) - (List.flatten - (List.map (elab_gcc_attr loc env) l)))) + (List.map (enter_gcc_attr loc) + (List.flatten + (List.map (elab_gcc_attr loc env) l))) | PACKED_ATTR (args, loc) -> - [Attr("__packed__", List.map (elab_attr_arg loc env) args)] + enter_gcc_attr loc + (Attr("__packed__", List.map (elab_attr_arg loc env) args)) | ALIGNAS_ATTR ([a], loc) -> warning loc Celeven_extension "'_Alignas' is a C11 extension"; begin match elab_attr_arg loc env a with | AInt n -> - if is_power_of_two n || n = 0L then - [AAlignas (Int64.to_int n)] - else begin - error loc "requested alignment is not a power of 2"; [] - end + if check_alignment loc n then [AAlignas (Int64.to_int n)] else [] | _ -> error loc "requested alignment is not an integer constant"; [] | exception Wrong_attr_arg -> error loc "bad _Alignas value"; [] end diff --git a/cparser/PackedStructs.ml b/cparser/PackedStructs.ml index e1287eb8..a2c91c0a 100644 --- a/cparser/PackedStructs.ml +++ b/cparser/PackedStructs.ml @@ -81,47 +81,33 @@ let transf_field_decl mfa swapped loc env struct_id f = (* Rewriting struct declarations *) let transf_struct_decl mfa msa swapped loc env struct_id attrs ml = + let attrs' = + remove_custom_attributes ["packed";"__packed__"] attrs in let ml' = List.map (transf_field_decl mfa swapped loc env struct_id) ml in - if msa = 0 then (attrs, ml') else begin - let al' = (* natural alignment of the transformed struct *) - List.fold_left - (fun a f' -> max a (safe_alignof loc env f'.fld_typ)) - 1 ml' in - (set_alignas_attr (max msa al') attrs, ml') + if msa = 0 then (attrs', ml') else begin + (* [Cutil.composite_info_def] takes packing parameters into account. + Hence the alignment it returns is the correct alignment for + the transformed struct. *) + let ci = Cutil.composite_info_def env Struct attrs ml in + match ci.ci_alignof with + | None -> error loc "incomplete struct"; (attrs', ml') + | Some al -> (set_alignas_attr al attrs', ml') end (* Rewriting composite declarations *) -let is_pow2 n = n > 0 && n land (n - 1) = 0 - -let packed_param_value loc n = - let m = Int64.to_int n in - if n <> Int64.of_int m then - (error loc "__packed__ parameter `%Ld' is too large" n; 0) - else if m = 0 || is_pow2 m then - m - else - (error loc "__packed__ parameter `%Ld' must be a power of 2" n; 0) - let transf_composite loc env su id attrs ml = match su with | Union -> (attrs, ml) | Struct -> let (mfa, msa, swapped) = match find_custom_attributes ["packed";"__packed__"] attrs with - | [] -> (0L, 0L, false) - | [[]] -> (1L, 0L, false) - | [[AInt n]] -> (n, 0L, false) - | [[AInt n; AInt p]] -> (n, p, false) - | [[AInt n; AInt p; AInt q]] -> (n, p, q <> 0L) - | _ -> - error loc "ill-formed or ambiguous __packed__ attribute"; - (0L, 0L, false) in - let mfa = packed_param_value loc mfa in - let msa = packed_param_value loc msa in - let attrs' = remove_custom_attributes ["packed";"__packed__"] attrs in - transf_struct_decl mfa msa swapped loc env id attrs' ml + | [] -> (0, 0, false) + | [_] -> Cutil.packing_parameters attrs + | _ -> error loc "multiple __packed__ attributes"; + (0, 0, false) in + transf_struct_decl mfa msa swapped loc env id attrs ml (* Accessor functions *) diff --git a/test/regression/Results/packedstruct1-32 b/test/regression/Results/packedstruct1-32 index e4bca769..e7d1c296 100644 --- a/test/regression/Results/packedstruct1-32 +++ b/test/regression/Results/packedstruct1-32 @@ -1,25 +1,37 @@ sizeof(struct s1) = 14 +precomputed sizeof(struct s1) = 14 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s1 = {x = 123, y = -456, z = 3.14159} sizeof(struct s2) = 16 +precomputed sizeof(struct s2) = 16 &s2 mod 16 = 0 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s2 = {x = 57, y = -456, z = 3.14159} sizeof(struct s3) = 31 +precomputed sizeof(struct s3) = 31 offsetof(s) = 29 +precomputed offsetof(s) = 29 s3 = {x = 123, y = 45678, z = 2147483649, v = -456, w = -1234567, p is ok, t = {111,222,333}, s = {'o','k'}} sizeof(struct s4) = 16 +precomputed sizeof(struct s4) = 16 offsetof(x) = 0, offsetof(y) = 4, offsetof(z) = 8 +precomputed offsetof(x) = 0, offsetof(y) = 4, offsetof(z) = 8 s4 = {x = 123, y = -456, z = 3.14159} sizeof(struct s5) = 14 +precomputed sizeof(struct s5) = 14 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s5 = {x = 123, y = -456, z = 3.14159} sizeof(struct s6) = 14 +precomputed sizeof(struct s6) = 14 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s62 = {x = 123, y = -456, z = 3.14159} diff --git a/test/regression/Results/packedstruct1-64 b/test/regression/Results/packedstruct1-64 index c2a8bcd2..d255595f 100644 --- a/test/regression/Results/packedstruct1-64 +++ b/test/regression/Results/packedstruct1-64 @@ -1,25 +1,37 @@ sizeof(struct s1) = 14 +precomputed sizeof(struct s1) = 14 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s1 = {x = 123, y = -456, z = 3.14159} sizeof(struct s2) = 16 +precomputed sizeof(struct s2) = 16 &s2 mod 16 = 0 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s2 = {x = 57, y = -456, z = 3.14159} sizeof(struct s3) = 35 +precomputed sizeof(struct s3) = 35 offsetof(s) = 33 +precomputed offsetof(s) = 33 s3 = {x = 123, y = 45678, z = 2147483649, v = -456, w = -1234567, p is ok, t = {111,222,333}, s = {'o','k'}} sizeof(struct s4) = 16 +precomputed sizeof(struct s4) = 16 offsetof(x) = 0, offsetof(y) = 4, offsetof(z) = 8 +precomputed offsetof(x) = 0, offsetof(y) = 4, offsetof(z) = 8 s4 = {x = 123, y = -456, z = 3.14159} sizeof(struct s5) = 14 +precomputed sizeof(struct s5) = 14 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s5 = {x = 123, y = -456, z = 3.14159} sizeof(struct s6) = 14 +precomputed sizeof(struct s6) = 14 offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 +precomputed offsetof(x) = 0, offsetof(y) = 2, offsetof(z) = 6 s62 = {x = 123, y = -456, z = 3.14159} diff --git a/test/regression/packedstruct1.c b/test/regression/packedstruct1.c index 8b138dd4..5d3e7124 100644 --- a/test/regression/packedstruct1.c +++ b/test/regression/packedstruct1.c @@ -2,8 +2,18 @@ #include +/* offsetof is the offset computed by the verified front-end (cfrontend/) */ #define offsetof(s,f) (int)&(((struct s *)0)->f) +/* boffsetof is the offset computed by the elaborator (cparser/) */ +#define boffsetof(s,f) (int)__builtin_offsetof(struct s, f) + +/* szof is the size computed by the verified front-end (cfrontend/) */ +#define szof(s) (int) sizeof(struct s) + +/* bszof is the size computed by the elaborator (cparser/) */ +#define bszof(s) (int) sizeof(char [sizeof(struct s)]) + /* Simple packing */ struct __packed__(1) s1 { unsigned short x; int y; double z; }; @@ -11,9 +21,12 @@ struct __packed__(1) s1 { unsigned short x; int y; double z; }; void test1(void) { struct s1 s1; - printf("sizeof(struct s1) = %d\n", sizeof(struct s1)); + printf("sizeof(struct s1) = %d\n", szof(s1)); + printf("precomputed sizeof(struct s1) = %d\n", bszof(s1)); printf("offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", offsetof(s1,x), offsetof(s1,y), offsetof(s1,z)); + printf("precomputed offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", + boffsetof(s1,x), boffsetof(s1,y), boffsetof(s1,z)); s1.x = 123; s1.y = -456; s1.z = 3.14159; printf("s1 = {x = %d, y = %d, z = %.5f}\n\n", s1.x, s1.y, s1.z); } @@ -28,10 +41,13 @@ struct s2 s2; void test2(void) { - printf("sizeof(struct s2) = %d\n", sizeof(struct s2)); + printf("sizeof(struct s2) = %d\n", szof(s2)); + printf("precomputed sizeof(struct s2) = %d\n", bszof(s2)); printf("&s2 mod 16 = %d\n", ((int) &s2) & 0xF); printf("offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", offsetof(s2,x), offsetof(s2,y), offsetof(s2,z)); + printf("precomputed offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", + boffsetof(s2,x), boffsetof(s2,y), boffsetof(s2,z)); s2.x = 12345; s2.y = -456; s2.z = 3.14159; printf("s2 = {x = %d, y = %d, z = %.5f}\n\n", s2.x, s2.y, s2.z); } @@ -55,8 +71,10 @@ void test3(void) { char xx; - printf("sizeof(struct s3) = %d\n", sizeof(struct s3)); + printf("sizeof(struct s3) = %d\n", szof(s3)); + printf("precomputed sizeof(struct s3) = %d\n", bszof(s3)); printf("offsetof(s) = %d\n", offsetof(s3,s)); + printf("precomputed offsetof(s) = %d\n", boffsetof(s3,s)); s3.x = 123; s3.y = 45678; s3.z = 0x80000001U; @@ -82,9 +100,13 @@ struct s4 { unsigned short x; int y; double z; }; void test4(void) { struct s4 s4; - printf("sizeof(struct s4) = %d\n", sizeof(struct s4)); + + printf("sizeof(struct s4) = %d\n", szof(s4)); + printf("precomputed sizeof(struct s4) = %d\n", bszof(s4)); printf("offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", offsetof(s4,x), offsetof(s4,y), offsetof(s4,z)); + printf("precomputed offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", + boffsetof(s4,x), boffsetof(s4,y), boffsetof(s4,z)); s4.x = 123; s4.y = -456; s4.z = 3.14159; printf("s4 = {x = %d, y = %d, z = %.5f}\n\n", s4.x, s4.y, s4.z); } @@ -96,9 +118,13 @@ struct __attribute((packed)) s5 { unsigned short x; int y; double z; }; void test5(void) { struct s5 s5; - printf("sizeof(struct s5) = %d\n", sizeof(struct s5)); + + printf("sizeof(struct s5) = %d\n", szof(s5)); + printf("precomputed sizeof(struct s5) = %d\n", bszof(s5)); printf("offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", offsetof(s5,x), offsetof(s5,y), offsetof(s5,z)); + printf("precomputed offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", + boffsetof(s5,x), boffsetof(s5,y), boffsetof(s5,z)); s5.x = 123; s5.y = -456; s5.z = 3.14159; printf("s5 = {x = %d, y = %d, z = %.5f}\n\n", s5.x, s5.y, s5.z); } @@ -110,9 +136,13 @@ struct s6 { unsigned short x; int y; double z; } __attribute((packed)) const s6 void test6(void) { struct s6 s62; - printf("sizeof(struct s6) = %d\n", sizeof(struct s6)); + + printf("sizeof(struct s6) = %d\n", szof(s6)); + printf("precomputed sizeof(struct s6) = %d\n", bszof(s6)); printf("offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", offsetof(s6,x), offsetof(s6,y), offsetof(s6,z)); + printf("precomputed offsetof(x) = %d, offsetof(y) = %d, offsetof(z) = %d\n", + boffsetof(s6,x), boffsetof(s6,y), boffsetof(s6,z)); s62.x = 123; s62.y = -456; s62.z = 3.14159; printf("s62 = {x = %d, y = %d, z = %.5f}\n\n", s62.x, s62.y, s62.z); } -- cgit