简体   繁体   English

C sizeof宏的等价物

[英]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). 当然,这不起作用,因为预处理器无法使用sizeof (至少, 这个答案似乎表明了这一点 )。

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? 是否有一个简单的解决方法,我可以用来获取与C宏一起使用的数据结构的sizeof ,或者我只是SOL?

You cannot do it in preprocessor, but you do not need to. 你不能在预处理器中做到这一点,但你不需要。 Just generate a plain if in your macro: 只是产生一个普通的if在您的宏:

#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. sizeof是一个常量表达式,将常量与常量进行比较也是不变的。 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. 任何理智的C编译器都会优化掉在编译时始终为false的分支 - 常量折叠是最基本的优化之一。 You lose the #warning , though. 但是你失去了#warning

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 ). 如果您使用的是autoconf或其他构建配置系统,则可以在配置时检查数据结构的大小并写出标头(如#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. 否则是的,你运气不好。

You're out of luck - the preprocessor doesn't even know what a struct is, let alone any way to work out its size. 你运气不好 - 预处理器甚至不知道结构是什么,更不用说任何方法来计算它的大小了。

In a case like this you could just #define a constant to what you happen to know the size of the struct is, then statically assert that it's actually equal to the size using the negative-sized array trick. 在这种情况下你可以#define一个常量,你知道结构的大小是什么,然后静态断言它实际上等于使用负大小数组技巧的大小。

Also you could try just doing if (sizeof(Entry) == 12) , and see whether your compiler is capable of evaluating the branch condition at compile time and removing dead code. 你也可以尝试if (sizeof(Entry) == 12) ,看看你的编译器是否能够在编译时评估分支条件并删除死代码。 It's not that big an ask. 这不是一个大问题。

This probably won't help, but if you have the ability to do this in C++ you can use a template to cause the compiler to dispatch to the appropriate loop at compile time: 这可能没有帮助,但如果您能够在C ++中执行此操作,则可以使用模板使编译器在编译时调度到适当的循环:

template <std::size_t SizeOfEntry>
void process_entry_loop(...)
{
    // ... the nonoptimized version of the loop
}

template <>
void process_entry_loop<12>(...)
{
    // ... the optimized version of the loop
}

// ...

process_entry_loop<sizeof(Entry)>(...);

我想到了另外两种方法 - 编写一个小应用程序来编写展开的循环,或者在Duff的设备上使用具有预期结构大小的变体。

If you want the smallest possible size for the struct (or to align it to a 4-byte boundary, or whatever), you can use the packed or aligned attributes. 如果您想要结构的最小可能大小(或将其与4字节边界或其他任何对齐),则可以使用packed或aligned属性。

In Visual C++, you can use #pragma pack , and in GCC you can use __attribute__((packed)) and __attribute__((aligned(num-bytes)). 在Visual C ++中,您可以使用#pragma pack ,在GCC中可以使用__attribute __((packed))和__attribute __((aligned(num-bytes))。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM