用ntohl()初始化一个const变量

时间:2014-02-13 23:22:48

标签: c htonl

我正在尝试使用适当的字节交换值初始化全局范围的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)”或类似的在编译时无法计算的东西。长号。

我能做些什么来达到同样目的吗?我需要初始化适当的endness的值,我希望它是一个全局范围的const。是否有任何方法可以说服gcc这样做,而不是滚动我自己的类似ntohl的宏?

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

2 个答案:

答案 0 :(得分:3)

标准的第6.7.8 / 4节读取

  

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

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

但无论如何全局变量都很糟糕,我怀疑这可能是一个不成熟的优化。简单的解决方法是直接在代码中使用表达式,这在big-endian平台上根本不起作用,例如。

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

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

#define POTRZEBIE ntohl(0x11223344)

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

对于具有自动存储的变量,const限定符表示单个赋值,因此上述用法没有问题。

答案 1 :(得分:2)

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