I\'m trying to write a tool that will take as input some C code containing structs. It will compile the code, then find and output the size and offset of any padding the com
Have your tool parse the struct definition to find the names of the fields, then generate C code that prints a description of the struct padding, and finally compile and run that C code. Sample Perl code for the second part:
printf "const char *const field_names[] = {%s};\n",
join(", ", map {"\"$_\""} @field_names);
printf "const size_t offsets[] = {%s, %s};\n",
join(", ", map {"offsetof(struct $struct_name, $_)"} @field_names),
"sizeof(struct $struct_name)";
print <<'EOF'
for (i = 0; i < sizeof(field_names)/sizeof(*field_names); i++) {
size_t padding = offsets[i+1] - offsets[i];
printf("After %s: %zu bytes of padding\n", field_names[i], padding);
}
EOF
C is very difficult to parse, but you're only interested in a very small part of the language, and it sounds like you have some control over your source files, so a simple parser should do the trick. A search of CPAN turns up Devel::Tokenizer::C
and a few C::
modules as candidates (I know nothing about them other than their names). If you really need an accurate C parser, there is Cil, but you have to write your analysis in Ocaml.
I don't believe that any general-purpose facility exists for introspection/reflection in C. That's what Java or C# are for.
You could use Exuberant Ctags to parse your source files instead of using a CPAN module or hacking something up yourself. For instance, for the following code:
typedef struct _foo { int a; int b; } foo;
ctags emits the following:
_foo x.c /^typedef struct _foo {$/;" s file: a x.c /^ int a;$/;" m struct:_foo file: b x.c /^ int b;$/;" m struct:_foo file: foo x.c /^} foo;$/;" t typeref:struct:_foo file:
The first, fourth, and fifth columns should be enough for you to determine what struct types exist and what their members are. You could use that information to generate a C program that determines how much padding each struct type has.
If you have access to Visual C++, you can add the following pragma to have the compiler spit out where and how much padding was added:
#pragma warning(enable : 4820)
At that point you can probably just consume the output of cl.exe and go party.