2

15 年間 C コードを書いてきましたが、このようなコードは見たことがなく、どのように機能するのかわかりません。これは、何らかの方法で複数行のコードが整数値に解決される C99 コードを中心にしています。これは libplist から来ています。具体的にはhereです。394 行目から始まります。ここでは、構造体の uint64_t メンバーに、マクロ UINT_TO_HOST の結果が割り当てられています。

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

UINT_TO_HOST は、符号なし整数へのポインターと、整数のバイト単位のサイズを受け取るマクロです。マクロは、異なる uint サイズの一連のポインターへの共用体を定義し、マクロに渡された 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 は基本的に一連の中括弧 {} 内の 3 行のコードに解決されるため、問題は UINT_TO_HOST が実際に data->intval に値を返す方法です。同じことが get_unaligned 内で発生しているように見えます。おそらく最後のステートメント

__p->_v;

返されるものです。この機能は何と呼ばれていますか?この「機能」に関するドキュメントを参照できる人はいますか?

4

2 に答える 2

4

これはステートメント式と呼ばれ、GNU 拡張です。ここに、あなたが読みたいかもしれないいくつかのドキュメントがあります。

于 2013-08-03T20:56:01.353 に答える