C語言中文網 目錄
首頁 > 編程筆記 > C語言筆記 閱讀:1,827

_Generic關鍵字及其語法和應用(C11標準),C語言_Generic詳解

對接觸過面向對象程序設計的程序員來講,相信各位對泛型編程并不陌生。在 C11 標準中,_Generic 關鍵字可以讓 C 語言也如同 C++ 等面向對象程序設計語言一樣,使其支持輕量級的泛型編程設計。

利用 _Generic 關鍵字,可以簡單地將一組具有不同類型卻有相同功能的函數抽象為一個統一的接口,語法形式如下:

generic-selection:
    _Generic (assignment-expression, generic-assoc-list)
generic-assoc-list:
    generic-association
    generic-assoc-list , generic-association
generic-association:
    type-name : assignment-expression
    default : assignment-expression

與 sizeof 與 typeof 類似,_Generic 中的 assignment-expression 只用于在編譯時獲得該表達式的類型,而不會對該表達式做運行時計算,如以下代碼所示。
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#define getTypeName(x) _Generic((x), _Bool:"_Bool",\
    char: "char", \
    signed char: "signed char", \
    unsigned char: "unsigned char", \
    short int: "short int", \
    unsigned short int: "unsigned short int", \
    int: "int", \
    unsigned int: "unsigned int", \
    long int: "long int", \
    unsigned long int: "unsigned long int", \
    long long int: "long long int", \
    unsigned long long int: "unsigned long long int", \
    float: "float", \
    double: "double", \
    long double: "long double", \
    char *: "pointer to char", \
    void *: "pointer to void", \
    int *: "pointer to int")
int main(void)
{
    char c = 'a';
    size_t s;
    ptrdiff_t p;
    intmax_t i;
    int arr[3] = { 0 };
    printf("s is '%s'\n", getTypeName(s));
    printf("p is '%s'\n", getTypeName(p));
    printf("i is '%s'\n", getTypeName(i));
    printf("c is '%s'\n", getTypeName(c));
    printf("arr is '%s'\n", getTypeName(arr));
    printf("0x7FFFFFFF is '%s'\n", getTypeName(0x7FFFFFFF));
    printf("0xFFFFFFFF is '%s'\n", getTypeName(0xFFFFFFFF));
    printf("0x7FFFFFFFU is '%s'\n", getTypeName(0x7FFFFFFFU));
}
運行結果為:
s is 'unsigned int'
p is 'int'
i is 'long long int'
c is 'char'
arr is 'pointer to int'
0x7FFFFFFF is 'int'
0xFFFFFFFF is 'unsigned int'
0x7FFFFFFFU is 'unsigned int'

除此之外,還必須保證 generic-association-list 中有與 assignment-expression 類型相同的 generic-association 與之對應,否則編譯就會報錯。例如,在上面代碼的main函數中添加如下兩行代碼:
float *fp=NULL;
printf("fp is '%s'\n", getTypeName(fp));
很顯然,generic-assoc-list 中沒有 generic-association 與 fp 相匹配的類型,從而導致編譯出錯,如圖 1 所示。


圖 1 類型不匹配

要解決圖 1 這種類型不匹配時導致的編譯錯誤,你可以在 generic-association-list 中添加 default 處理,那么編譯就能夠順利進行,如下面的代碼所示:
#define getTypeName(x) _Generic((x), _Bool:"_Bool",\
    char: "char", \
    signed char: "signed char", \
    unsigned char: "unsigned char", \
    short int: "short int", \
    unsigned short int: "unsigned short int", \
    int: "int", \
    unsigned int: "unsigned int", \
    long int: "long int", \
    unsigned long int: "unsigned long int", \
    long long int: "long long int", \
    unsigned long long int: "unsigned long long int", \
    float: "float", \
    double: "double", \
    long double: "long double", \
    char *: "pointer to char", \
    void *: "pointer to void", \
    int *: "pointer to int",\
    default: "other")
現在,如果編譯器發現 generic-assoc-list 中沒有 generic-association 與 fp 相匹配的類型時,將默認執行 default 處理,運行結果為:

s is 'unsigned int'
p is 'int'
i is 'long long int'
c is 'char'
arr is 'pointer to int'
fp is 'other'
0x7FFFFFFF is 'int'
0xFFFFFFFF is 'unsigned int'
0x7FFFFFFFU is 'unsigned int'

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo