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

这个C代码块如何解析为整数赋值?,c,macros,block,c99,C,Macros,Block,C99,好的,在写C代码的15年中,我从未见过这样的代码,我也不知道它是如何工作的。它以一些C99代码为中心,其中多行代码以某种方式解析为一个整数值。具体来说,它来自libplist。好的,它从第394行开始,在该行中,结构的uint64_t成员被分配宏UINT_TO_HOST的结果 data->intval = UINT_TO_HOST(&data->intval, size); UINT_TO_HOST是一个宏,它接受指向无符号整数的指针以及整数的大小(以BTE为单位)。宏定义

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

data->intval = UINT_TO_HOST(&data->intval, size);
UINT_TO_HOST是一个宏,它接受指向无符号整数的指针以及整数的大小(以BTE为单位)。宏定义一个与一组不同uint大小的指针的并集,然后设置传递给宏的uint指针的地址。然后,它继续对齐内存中的uint,以便正确地将其与另一个宏进行字节交换。第172行定义了UINT_到_主机

#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使用结构和gcc属性packed执行一个技巧,该属性返回内存中基于类型对齐的指针值

  #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)) 
#定义be64toh(x)(((x)和0xFF00000000000000ull)>>56)\
|((x)和0x00FF000000000000ull)>>40)\
|((x)和0x0000FF0000000000ull)>>24)\
|((x)和0x000000FF00000000ull)>>8)\

|(((x)&0x00000000FF000000ull)这称为语句表达式,是GNU扩展。某些文档可能需要阅读。

这称为语句表达式,是GNU扩展。某些文档可能需要阅读。

正如其他人指出的,宏使用“表达中的陈述”

但宏观经济本身的结构并不完善。 小心。宏的代码可能会被破坏,因为里面有
{}

例如:

union plist_uint_ptr __up;
__up.src = 3;
UINT_TO_HOST(__up.src, 8);
宏展开后,会得到一句话:
\uuuuuu up.src=\uuu up.src;
,它只能给出一个垃圾值,因为对象
\uu up
已在宏的块范围内再次定义

最近在这里讨论了此类问题(第1节的第一部分,然后跳到第5节):

问题在于内部变量
\uuuu up
隐藏了外部变量
\uu up
的值,并且宏无法按预期工作。

因此,它是不可重用的代码。

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

但宏观经济本身的结构并不完善。 小心。宏的代码可能会被破坏,因为里面有
{}

例如:

union plist_uint_ptr __up;
__up.src = 3;
UINT_TO_HOST(__up.src, 8);
宏展开后,会得到一句话:
\uuuuuu up.src=\uuu up.src;
,它只能给出一个垃圾值,因为对象
\uu up
已在宏的块范围内再次定义

最近在这里讨论了此类问题(第1节的第一部分,然后跳到第5节):

问题在于内部变量
\uuuu up
隐藏了外部变量
\uu up
的值,并且宏无法按预期工作。

因此,它是不可重用的代码。

太棒了!谢谢H2CO3,这回答了我的问题。摘自您在语句表达式上提供的链接:复合语句中的最后一个内容应该是一个表达式,后跟分号;此子表达式的值充当整个构造的值。@hokey不客气。看到您你是一名经验丰富的C程序员(可能比我更有经验):您可能对良好实践感兴趣/敏感。您在过去一年半的时间里没有看到过这种构造,这是一个很好的理由。这不是标准的、不可移植的,因此,我建议您完全避免使用。我同意。这周尝试移植代码时让我相当头疼。宏有它们自己的功能但它们缺乏类型安全性和其他缺点只会使代码难以维护、读取,并且容易出错。更不用说调试这段代码的好运了。太棒了!感谢H2CO3,这回答了我的问题。摘自您提供的语句表达式链接:复合语句中的最后一件事应该是b后面的表达式y是分号;此子表达式的值作为整个构造的值。@hokey不客气。看到你是一名经验丰富的C程序员(可能比我更有经验):您可能对良好实践感兴趣/敏感。您在过去一年半的时间里没有看到过这种构造,这是一个很好的理由。这不是标准的、不可移植的,因此,我建议您完全避免使用。我同意。这周尝试移植代码时让我相当头疼。宏有它们自己的功能但是它们缺乏类型安全性和其他缺点使得代码很难维护、读取,并且容易出错。更不用说调试时运气好了。