ここでチャレンジ問題です。配列である可能性がある未知の変数タイプのマスク ビットマップを作成したいと考えています。例えば、
char ch;
int i;
int i_arr[2];
printf("The ordinary type for ch is %lu bytes.\n", sizeof(ORDINARY_TYPE(ch)));
printf("The ordinary type for i is %lu bytes.\n", sizeof(ORDINARY_TYPE(i)));
printf("The ordinary type for i_arr is %lu bytes.\n", sizeof(ORDINARY_TYPE(i_arr)));
出力は次のようになります。
The ordinary type for ch is 1 bytes.
The ordinary type for i is 4 bytes.
The ordinary type for i_arr is 4 bytes.
不可能に聞こえますか?そうではありません。あなたにジャンプスタートを与えるために、私は私の「解決策」を提供します - それは非常にGCC特有のものであることに注意してください。
#define IS_PTR(X) \
__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(X), char*), \
1, \
__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(X), int8_t*), \
1, \
__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(X), uint8_t*), \
1, \
(((uintptr_t)((1 ? (X) : (uintmax_t)0)+1) - \
(uintptr_t)(1 ? (X) : (uintmax_t)0)) != 1)? 1 : 0 \
)))
#define ORDINARY_TYPE(X) \
typeof(* __builtin_choose_expr( \
__builtin_types_compatible_p( \
typeof(*(IS_PTR(X)? (X) : (&(X)))), void), \
((X)), \
(&(X)) \
))
ここでは、 ifがポインターである場合にIS_PTR(X)? (X) : (&(X))
返される結果を利用しています。ただし、結果として、GCC コンパイラは次の警告を表示します (のタイプによって異なります)。void *
X
X
warning: pointer/integer type mismatch in conditional expression [enabled by default]
warning: pointer type mismatch in conditional expression [enabled by default]
誰でもこれらの警告を受けずにこれを実行して、「より使いやすく」することはできますか?
使用する
私は一般的なGPIO構成ライブラリに取り組んでいます(笑)。私はかなりしっかりしたものを持っていると思いますが、他のプロセッサについてはより厳密なテストが必要になることは明らかです. 「金塊」の 1 つは、GPIO ピンのプロパティを構成することです。
CPU_GPIO_CONFIG_PROP(gpio, pupd, 2); // Pull up/down, Open Drain, or none
CPU_GPIO_CONFIG_PROP(gpio, af, 4); // Alternative Functions
CPU_GPIO_CONFIG_PROP
そのように定義されている場所は、
extern struct cpu_gpio;
#define CPU_GPIO_CONFIG_PROP(_gpio, _prop, _size) ({ \
struct cpu_gpio *bus = (_gpio)->bus_addr; \
ORDINARY_TYPE( ((struct cpu_gpio *) 0)->_prop) prop_type; \
const size_t prop_size = sizeof(prop_type); \
const unsigned short pin = ((_size)*(_gpio)->pin) % (8*prop_size); \
const typeof(prop_type) mask = ~(~((typeof(prop_type)) 0x0) << _size); \
typeof(prop_type) *p = ((typeof(prop_type) *) &bus->_prop \
+ ((_size)*((_gpio)->pin)/(8*prop_size))); \
*p = (*p & ~(mask << pin)) | (((typeof(prop_type)) gpio->_prop) << pin); \
})
ふぅ!さて、誰かがもう一度「なぜ?」と尋ねるでしょう。(@nneonneo)...簡単な答えは (これは長くなりすぎるため)、各 GPIO プロパティは通常8*_size
< sizeof(int)
(32 ビット ARM プロセッサ) であるということです。これ_size
は、プロパティがそれを記述するのに必要なビット数です。ただし、プロパティがこの要件を超えて8*_size
>になる可能性がありますsizeof(int)
。この場合、プロパティはint[n]
メモリ内のスペースを占有し、計算するために追加の計算が必要になります (上記で既に行ったように)。私の例では、af
説明するのに 4 ビットかかります (5 つの代替機能から選択できます)。16 ピンの場合、これは 4*16 > 32 となるためint[2]
、説明が必要です。GPIOプロパティの!
ところで、価値があると感じたら、自由に再利用してください。少しだけ声をかけてください!
いくつかのメモ
- これは
void*
、intXX_t **
(または、複数のポインターを参照する任意のポインター、したがって&(int[n])
であっても(void *)ARR == (void *)&ARR
) では機能しません。 __builtin_types_compatible_p(typeof(char), int8_t, ...)
false と評価されます。(uintptr_t)((X)+1) - (uintptr_t)(X) != 1
ポインタ演算のテストです。