So I'm optimizing some code by unrolling some loops (yes, I know that I should rely on my compiler to do this for me, but I'm not working with my choice of compilers) and I wanted to do so somewhat gracefully so that, in case my data size changes due to some edits in the future, the code will degrade elegantly.
Something like:
typedef struct {
uint32_t alpha;
uint32_t two;
uint32_t iii;
} Entry;
/*...*/
uint8_t * bytes = (uint8_t *) entry;
#define PROCESS_ENTRY(i) bytes[i] ^= 1; /*...etc, etc, */
#if (sizeof(Entry) == 12)
PROCESS_ENTRY( 0);PROCESS_ENTRY( 1);PROCESS_ENTRY( 2);
PROCESS_ENTRY( 3);PROCESS_ENTRY( 4);PROCESS_ENTRY( 5);
PROCESS_ENTRY( 6);PROCESS_ENTRY( 7);PROCESS_ENTRY( 8);
PROCESS_ENTRY( 9);PROCESS_ENTRY(10);PROCESS_ENTRY(11);
#else
# warning Using non-optimized code
size_t i;
for (i = 0; i < sizeof(Entry); i++)
{
PROCESS_ENTRY(i);
}
#endif
#undef PROCESS_ENTRY
This not working, of course, since sizeof
isn't available to the pre-processor (at least, that's what this answer seemed to indicate).
Is there an easy workaround I can use to get the sizeof
a data structure for use with a C macro, or am I just SOL?
In your case 8 bytes.
The sizeof operator yields an integer equal to the size of the specified object or type in bytes. (Strictly, sizeof produces an unsigned integer value whose type, size_t , is defined in the header <stddef. h>.) A sizeof cannot be used in a #if directive, because the preprocessor does not parse type names.
Sizeof is neither a macro nor a function. Its a operator which is evaluated at compile time.
In the C Programming Language, the #define directive allows the definition of macros within your source code. These macro definitions allow constant values to be declared for use throughout your code. Macro definitions are not variables and cannot be changed by your program code like variables.
You cannot do it in preprocessor, but you do not need to. Just generate a plain if
in your macro:
#define PROCESS_ENTRY(i) bytes[i] ^= 1; /*...etc, etc, */
if (sizeof(Entry) == 12) {
PROCESS_ENTRY( 0);PROCESS_ENTRY( 1);PROCESS_ENTRY( 2);
PROCESS_ENTRY( 3);PROCESS_ENTRY( 4);PROCESS_ENTRY( 5);
PROCESS_ENTRY( 6);PROCESS_ENTRY( 7);PROCESS_ENTRY( 8);
PROCESS_ENTRY( 9);PROCESS_ENTRY(10);PROCESS_ENTRY(11);
} else {
size_t i;
for (i = 0; i < sizeof(Entry); i++) {
PROCESS_ENTRY(i);
}
}
sizeof
is a constant expression, and comparing a constant against constant is also constant. Any sane C compiler will optimize away the branch that is always false at compile-time - constant folding is one of the most basic optimizations. You lose the #warning
, though.
If you are using autoconf or another build configuration system, you could check the size of the data structures at configuration time and write out headers (like #define SIZEOF_Entry 12
). Of course this gets more complicated when cross-compiling and such, but I am assuming your build and target architectures are the same.
Otherwise yes, you are out of luck.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With