Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C sizeof equivalent for macros

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?

like image 396
rampion Avatar asked Aug 20 '09 20:08

rampion


People also ask

What is macro size in C?

In your case 8 bytes.

Can sizeof be used in macro?

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.

Is sizeof () a macro or a function?

Sizeof is neither a macro nor a function. Its a operator which is evaluated at compile time.

What is #define size in C?

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.


2 Answers

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.

like image 189
Pavel Minaev Avatar answered Oct 21 '22 23:10

Pavel Minaev


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.

like image 9
Sean Bright Avatar answered Oct 22 '22 00:10

Sean Bright