A) 首先 line 16 輸出 error 才是正常的
ptr 的型別是 void*
因此 *ptr 會對應到 void
但是 void 是 incomplete type
所以只能屬於 default
B) C11 加入 _Generic 關鍵字是神奇的進展
前處理器只做簡單的字串處理
完全不會涉及到判斷 macro argument 的型別
如果要在前處理階段時完成會使設計難度大增
因此時至今日 _Generic 仍然在編譯階段處理
_Generic 的語法如下:
_Generic(controlling-expression, association-list)
where association-list | type-name ':' expression
[yacc syntax, (LA)LR] | association-list type-name ':' expression
事實上這並沒有想像中的糟 O.O
早期工程師遇到這種問題時
設計出了一套 hack 的方法 (compiler-dependent, GCC)
#define is_of(x, t) (__builtin_types_compatible_p(__typeof__(x), t))
#define print(x) do { if (is_of(x, int)) \
printf("num = %d\n", x); \
else if (is_of(x, char)) \
printf("char = %c\n", x); \
else abort(); } while (0)
int main (void)
{
char c = 'a';
int n = 10;
float f = 1.2;
print(n); // shows: num = 10
print(c); // char = a
print(f); // Aborted (core dumped)
}
這乍看下完美解決這個問題
但是當這樣的需求越來越大的時候
被編入語言標準的可能性就會大增
好確保能跨平臺使用沒問題
C) 原本的寫法會觸發編譯警告
雖然 _Gerenic 是 Generic Selection 沒錯
但是編譯器還是會在所有的 expression 裡檢查語意的正確性
由於輸入的型別並非固定
要同時滿足 printf 的 format specifier 本質上是不可能的
如果按照原先的代碼可能會產生
Wcast-align (Clang) 或是 Wstrict-aliasing (GCC) 等警告
因此比較好的寫法應該會是:
#define var_sp(x) _Generic((x), char: "%s%c\n", int: "%s%d\n")
#define prompt(x) _Generic((x), char: "char = ", int: "num = ")
int main (void)
{
char c = 'a';
int n = 10;
printf(var_sp(c), prompt(c), c);
printf(var_sp(n), prompt(n), n);
}
※ 引述《rice9547 (一碗飯)》之銘言:
:
: 預期的正確結果(Expected Output):
: line 13, 14 輸出正確
: line 16卻輸出 error
: 預期應該會和 line 13一樣
:
: 程式碼(Code):(請善用置底文網頁, 記得排版)
: https://ideone.com/1FaCEr