4

我正在尝试使用适当字节交换的值初始化全局范围的 const 变量。

#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>

const uint32_t a = ntohl(0x11223344);

int main(int argc, char const *argv[])
{
    printf("%08x\n", a);
    return 0;
}

使用 gcc 失败并显示“错误:初始化元素不是常量”。是的,好的,所以 gcc 头文件将 ntohl() 定义为一个函数或“do {...} while (0)”或类似的东西,在编译时无法评估。真可惜。

我能做些什么来达到同样的目的吗?我需要为适当的结束性初始化值,并且我希望它是一个全局范围的常量。除了滚动我自己的类似 ntohl 的宏之外,有没有办法说服 gcc 这样做?

(顺便说一句,我注意到 clang 定义了 ntohl() 以便可以在编译时对其进行评估。上面的代码示例与 clang 完美配合。不幸的是,我没有选择编译器。)

4

2 回答 2

3

标准的第 6.7.8/4 节内容如下

具有静态存储持续时间的对象的初始化程序中的所有表达式都应为常量表达式或字符串文字。

调用ntohl既不是常量表达式也不是字符串文字。你不能从这里到达那里。

但是无论如何全局变量都是不好的,我怀疑这可能是一个过早的优化。简单的解决方法是直接在代码中使用表达式,这在大端平台上完全没有影响,例如

void foo(void)
{
  const unit32_t a = ntohl(0x11223344);
  /* ... */
}

更好的是,使用预处理器宏,如

#define POTRZEBIE ntohl(0x11223344)

void bar(void)
{
  const unit32_t a = POTRZEBIE;
  /* ... */
}

在具有自动存储的变量上,const限定符表示单次赋值,所以上面的用法没有问题。

于 2014-02-13T23:41:59.130 回答
1

初始化它main()或使用类似的东西(假设 Linux):

 #include <endian.h>
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 const uint32_t a = 0x44332211;
 #else
 const uint32_t a = 0x11223344;
 #endif

也许

 #include <endian.h>
 #define A_ADDR 0x11223344
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 const uint32_t a = __bswap_constant_32(A_ADDR);
 #else
 const uint32_t a = A_ADDR;
 #endif
于 2014-02-13T23:34:40.237 回答