Re: [問題] void指標輸出值問題

作者: Hazukashiine (私は幸せです)   2017-11-16 09:24:13
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
作者: hunandy14 (Charlott.HonG)   2017-11-20 12:25:00
凄い~勉強になりました~
作者: james732 (好人超)   2017-11-16 10:55:00
完全不知道有這東西,感謝
作者: peterwu4 (notd)   2017-11-16 12:59:00
好厲害,推一個~
作者: ilikekotomi (Young)   2017-11-16 20:01:00
推 感謝分享
作者: wtchen (沒有存在感的人)   2017-11-16 20:57:00
已經躺進精華區囉
作者: sppmg (sppmg)   2017-11-16 22:32:00
好文,一直對 _Generic 感興趣。不過 tcc 不支援的樣子...
作者: Lipraxde (Lipraxde)   2017-11-16 22:58:00
要怎麼樣才能厲害到要出什麼警告都知道啊?

Links booklink

Contact Us: admin [ a t ] ucptt.com