5

所以我通过展开一些循环来优化一些代码(是的,我知道我应该依靠我的编译器来为我做这件事,但我没有使用我选择的编译器)我想这样做有点优雅所以万一我的数据大小由于将来的一些编辑而改变,代码将优雅地降级。

就像是:

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

当然,这不起作用,因为sizeof预处理器无法使用(至少,这就是这个答案似乎表明的)。

是否有一个简单的解决方法可以用来获取sizeof用于 C 宏的数据结构,或者我只是 SOL?

4

6 回答 6

17

您不能在预处理器中执行此操作,但您不需要这样做。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是一个常数表达式,将常数与常数进行比较也是常数。任何理智的 C 编译器都会优化掉在编译时总是错误的分支——常量折叠是最基本的优化之一。但是,您会丢失#warning

于 2009-08-20T21:08:19.280 回答
9

如果您使用autoconf或其他构建配置系统,您可以在配置时检查数据结构的大小并写出标题(如#define SIZEOF_Entry 12)。当然,当交叉编译等时,这会变得更加复杂,但我假设您的构建和目标架构是相同的。

否则,是的,你不走运。

于 2009-08-20T21:01:33.567 回答
5

你不走运 - 预处理器甚至不知道结构是什么,更不用说计算它的大小的任何方法了。

在这种情况下,您可以#define 一个常量来表示您碰巧知道结构的大小,然后使用负大小数组技巧静态断言它实际上等于大小。

你也可以尝试做if (sizeof(Entry) == 12),看看你的编译器是否能够在编译时评估分支条件并删除死代码。这不是一个大问题。

于 2009-08-20T21:05:46.600 回答
1

这可能无济于事,但是如果您有能力在 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)>(...);
于 2009-08-20T21:06:09.720 回答
1

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

于 2009-08-20T21:10:45.703 回答
-1

如果您想要结构的最小可能大小(或将其对齐到 4 字节边界,或其他),您可以使用打包或对齐属性。

在 Visual C++ 中,您可以使用#pragma pack,而在 GCC 中,您可以使用 __attribute__((packed)) 和 __attribute__((aligned(num-bytes))。

于 2009-08-20T21:01:45.440 回答