这个C代码块如何解析为整数赋值?

时间:2013-08-03 20:54:01

标签: c macros block c99

好的,在编写C代码的15年中,我从未见过像这样的代码,我不知道它是如何工作的。它以一些C99代码为中心,以某种方式将多行代码解析为整数值。它来自libplist,特别是here。好的,它从第394行开始,其中一个结构的uint64_t成员被赋予宏的结果UINT_TO_HOST

data->intval = UINT_TO_HOST(&data->intval, size);

UINT_TO_HOST是一个宏,它接受一个指向无符号整数的指针,以及整数的btes大小。宏定义了一组不同uint大小的指针的联合,然后将地址设置为传递给宏的uint指针。然后它继续将uint对齐到内存中,以便与另一个宏正确地进行字节交换。 UINT_TO_HOST在第172行定义

#define UINT_TO_HOST(x, n) \
({ \
    union plist_uint_ptr __up; \
    __up.src = x; \
    (n == 8 ? be64toh( get_unaligned(__up.u64ptr) ) : \
    (n == 4 ? be32toh( get_unaligned(__up.u32ptr) ) : \
    (n == 3 ? uint24_from_be( __up ) : \
    (n == 2 ? be16toh( get_unaligned(__up.u16ptr) ) : \
    *__up.u8ptr )))); \
})

得到未对齐做一个结构和gcc属性打包的技巧,它返回基于类型在内存中对齐的指针值。

  #define get_unaligned(ptr)              \
  ({                                              \
    struct __attribute__((packed)) {          \
      typeof(*(ptr)) __v;             \
    } *__p = (void *) (ptr);              \
    __p->__v;                     \
  })

be64toh只是做了一些掩饰和转移。

#define be64toh(x) ((((x) & 0xFF00000000000000ull) >> 56) \
                | (((x) & 0x00FF000000000000ull) >> 40) \
                | (((x) & 0x0000FF0000000000ull) >> 24) \
                | (((x) & 0x000000FF00000000ull) >> 8) \
                | (((x) & 0x00000000FF000000ull) << 8) \
                | (((x) & 0x0000000000FF0000ull) << 24) \
                | (((x) & 0x000000000000FF00ull) << 40) \
                | (((x) & 0x00000000000000FFull) << 56)) 

问题是UINT_TO_HOST如何实际将值返回到data-&gt; intval,因为UINT_TO_HOST基本上被解析为一组花括号{}内的3行代码。同样的事情似乎发生在get_unaligned里面,可能是最后一个声明

  

__对 - &GT; _v;

返回的是什么。这个功能叫做什么,任何人都可以指出这个'功能'的一些文档吗?

2 个答案:

答案 0 :(得分:4)

这称为语句表达式,它是GNU扩展。 Here's您可能想要阅读的一些文档。

答案 1 :(得分:0)

正如其他人所指出的,宏使用GCC语法“表达式中的语句”。

但宏观本身并不是很好。 小心点。该宏的代码可以被破坏,因为内部存在{ } 例如:

union plist_uint_ptr __up;
__up.src = 3;
UINT_TO_HOST(__up.src, 8);

在宏扩展之后,它获得了句子:__up.src = __up.src;,它只能给出一个垃圾值,因为在宏的块范围内再次定义了对象__up

这里最近讨论了这种麻烦(第1部分的第一部分,然后跳到第5部分):

How much is it possible to create fake-functions with macros in C?

问题是内部变量__up隐藏了外部变量__up的值,并且宏不能按预期工作。
因此,它是不可重用的代码。