![](/img/trans.png)
[英]Standalone Code-Block Works, But Function Call W/ Same Code Does Not (C Program)
[英]How does this C code-block get resolved to an integer assignment?
好的,在編寫C代碼的15年中,我從未見過這樣的代碼,而且我也不知道它是如何工作的。 它以某些C99代碼為中心,其中多行代碼被解析為整數值。 它來自libplist,特別是這里 。 好的,它從第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 )))); \
})
get unaligned使用結構和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;
是什么得到回報。 這個功能叫什么,任何人都可以指向該“功能”的一些文檔嗎?
正如其他人指出的那樣,宏使用GCC語法“表達式中的語句”。
但是宏本身的格式不正確。 小心點。 宏的代碼可能會被破壞,因為里面存在{ }
。
例如:
union plist_uint_ptr __up;
__up.src = 3;
UINT_TO_HOST(__up.src, 8);
宏擴展后,將獲得以下語句: __up.src = __up.src;
只能給出一個垃圾值,因為在宏的塊作用域中再次定義了對象__up
。
最近在這里討論了這種麻煩(第1部分的第一部分,然后跳到第5部分):
問題在於內部變量__up
隱藏了外部變量__up
的值,並且該宏無法按預期工作。
因此,它是不可重用的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.