2

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

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

UINT_TO_HOST 是一个宏,它接受一个指向无符号整数的指针,以及整数的字节大小。宏定义了一组不同 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 )))); \
})

get unaligned 使用 struct 和打包的 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->intval,因为 UINT_TO_HOST 基本上被解析为一组花括号 {} 内的 3 行代码。get_unaligned 内部似乎也发生了同样的事情,大概是最后一条语句

__p->_v;

是什么被退回。这个功能叫什么,任何人都可以指出关于这个“功能”的一些文档吗?

4

2 回答 2

4

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

于 2013-08-03T20:56:01.353 回答
0

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

但是宏本身并没有很好地形成。小心点。那个宏的代码是可以破解的,因为{ }里面的存在。
例如:

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

宏展开后得到语句:__up.src = __up.src;which only can give agarbage value,因为对象__up已经在宏的块范围内重新定义。

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

在 C 中使用宏创建伪函数的可能性有多大?

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

于 2013-08-26T23:23:34.387 回答