C Language
Generiskt urval
Sök…
Syntax
- _Generiskt (tilldelningsuttryck, generisk-associerad-lista)
parametrar
Parameter | detaljer |
---|---|
generic-assoc-lista | generisk-förening ELLER generisk-associerad-lista, generisk-förening |
generic-association | typnamn: tilldelningsuttryck ELLER standard: tilldelningsuttryck |
Anmärkningar
- Alla typkvalificeringar kommer att släppas under utvärderingen av
_Generic
primärt uttryck. -
_Generic
primärt uttryck utvärderas i översättningsfas 7 . Så faser som strängtillkoppling har avslutats före utvärderingen.
Kontrollera om en variabel är av en viss kvalificerad typ
#include <stdio.h>
#define is_const_int(x) _Generic((&x), \
const int *: "a const int", \
int *: "a non-const int", \
default: "of other type")
int main(void)
{
const int i = 1;
int j = 1;
double k = 1.0;
printf("i is %s\n", is_const_int(i));
printf("j is %s\n", is_const_int(j));
printf("k is %s\n", is_const_int(k));
}
Produktion:
i is a const int
j is a non-const int
k is of other type
Men om typen generisk makro implementeras så här:
#define is_const_int(x) _Generic((x), \
const int: "a const int", \
int: "a non-const int", \
default: "of other type")
Utgången är:
i is a non-const int
j is a non-const int
k is of other type
Detta beror på att alla typer av kvalificeringar släpps för utvärderingen av det kontrollerande uttrycket för ett _Generic
primärt uttryck.
Typgenerisk utskriftsmakro
#include <stdio.h>
void print_int(int x) { printf("int: %d\n", x); }
void print_dbl(double x) { printf("double: %g\n", x); }
void print_default() { puts("unknown argument"); }
#define print(X) _Generic((X), \
int: print_int, \
double: print_dbl, \
default: print_default)(X)
int main(void) {
print(42);
print(3.14);
print("hello, world");
}
Produktion:
int: 42
double: 3.14
unknown argument
Observera att om typen varken är int
eller double
skulle en varning genereras. För att eliminera varningen kan du lägga till den typen i print(X)
.
Generiskt urval baserat på flera argument
Om ett val på flera argument för ett typiskt generiskt uttryck önskas, och alla typer i fråga är aritmetiska typer, är ett enkelt sätt att undvika kapslade _Generic
uttryck att använda tillägg av parametrarna i det styrande uttrycket:
int max_int(int, int);
unsigned max_unsigned(unsigned, unsigned);
double max_double(double, double);
#define MAX(X, Y) _Generic((X)+(Y), \
int: max_int, \
unsigned: max_unsigned, \
default: max_double) \
((X), (Y))
Här kontrolleras det kontrollerande uttrycket (X)+(Y)
endast enligt dess typ och utvärderas inte. De vanliga omvandlingarna för aritmetiska operander utförs för att bestämma den valda typen.
För mer komplex situation kan ett val göras baserat på mer än ett argument till operatören genom att häcka dem tillsammans.
Detta exempel väljer mellan fyra externt implementerade funktioner som tar kombinationer av två int- och / eller strängargument och returnerar summan.
int AddIntInt(int a, int b);
int AddIntStr(int a, const char* b);
int AddStrInt(const char* a, int b );
int AddStrStr(const char* a, const char* b);
#define AddStr(y) \
_Generic((y), int: AddStrInt, \
char*: AddStrStr, \
const char*: AddStrStr )
#define AddInt(y) \
_Generic((y), int: AddIntInt, \
char*: AddIntStr, \
const char*: AddIntStr )
#define Add(x, y) \
_Generic((x) , int: AddInt(y) , \
char*: AddStr(y) , \
const char*: AddStr(y)) \
((x), (y))
int main( void )
{
int result = 0;
result = Add( 100 , 999 );
result = Add( 100 , "999" );
result = Add( "100" , 999 );
result = Add( "100" , "999" );
const int a = -123;
char b[] = "4321";
result = Add( a , b );
int c = 1;
const char d[] = "0";
result = Add( d , ++c );
}
Även om det verkar som om argument y
utvärderas mer än en gång är det inte 1 . Båda argumenten utvärderas endast en gång, i slutet av makro Add: ( x , y )
, precis som i ett vanligt funktionssamtal.
1 (Citat från: ISO: IEC 9899: 201X 6.5.1.1 Generiskt urval 3)
Det kontrollerande uttrycket för ett generiskt urval utvärderas inte.