表达式(二)
二、主表达式
主表达式(primary expressions)是在语句中可以单独使用的表达式,是构成更复杂表达式的组成部分。C语言中主表达式包括:标识符、常量、字符串字面量(string-literal)、括号表达式(parenthesized expression)和泛型选择(generic-selection)。
标识符作为主表达式使用时,必须在当前作用域内存在一个可见声明,并且该标识符是声明对象或者函数的普通标识符。如果声明为对象标识符,标识符是左值;如果声明为函数标识符,标识符是函数指示符(function designator)。
int data; //data是左值。 int func(void); //func是函数指示符。
对于常量主表达式,其类型取决于值和形式,例如:3.14类型是double类型;3.14f类型是float类型。
如果标识符表示枚举常量,则是常量主表达式,而不是标识符主表达式,例如:enum color{white, black};,这里white和black是常量表达式,而不是标识符表达式。
字符串字面量主表达式是左值,其类型与编码前缀有关,例如:U"中国"类型是char32_t *类型、L"中国"类型是wchar_t *类型。
括号表达式是主表达式;其类型、值和语义与非括号表达式(unparenthesized expression)相同,例如:5和(5),值都是5,类型都是int类型。如果非括号表达式分别是左值、函数指示符或者void类型表达式,那么括号表达式就是左值、函数指示符或者void类型表达式。括号表达式归类为主表达式,保证了括号运算符的优先级高于其它运算符。
泛型选择的语法格式如下所示:
_Generic(assignment-expression , generic-assoc-list)
其中_Generic是C语言关键词,assignment-expression是赋值表达式,generic-assoc-list是泛型关联列表;泛型关联列表由泛型关联构成,泛型关联(generic-association)之间使用逗号(,)分隔,泛型关联具有以下两种格式:
type-name : assignment-expression
default : assignment-expression
其中type-name是类型名,assignment-expression是赋值表达式。
每个泛型选择最多存在一个default泛型关联。泛型关联中的类型名应为完整对象类型(可变修改类型除外)。同一泛型选择中任意两个泛型关联的类型名不能是兼容类型。
#define FUNC(x) _Generic((x), \ wchar_t *: wchar_tFunc, \ char16_t *: char16_tFunc, \ char32_t *: char32_tFunc, \ default: charFunc \ )(x)
有些系统中wchar_t *类型和char16_t *类型是兼容类型;有些系统中则不是。在wchar_t *类型和char16_t *类型兼容的系统中,上述代码编译时会报错;在wchar_t *类型和char16_t *类型不兼容的系统中,上述代码可以正常编译。
控制表达式的类型像经过左值转换、数组到指针的转换或者函数到指针的转换的表达式类型。
#define TYPE(x) _Generic((x), \ int (*) (int): "int (*)(int) type.", \ default: "unknown type." \ ) int func(int i) { return i; } ... printf("%s\n", TYPE(func)); //func函数的类型为int (*) (int)。
左值转换会丢弃类型限定符(type qualifier)。
#define TYPE(x) _Generic((x), \ int : "int type", \ const int : "const int type", \ default: "unknown type." \ ) ... const int number = 10; printf("%s\n", TYPE(number)); //输出int type。
控制表达式的类型与泛型关联列表中最多一种类型兼容。如果泛型选择没有default泛型关联,则控制表达式的类型应与泛型关联列表中一种类型兼容。泛型选择的控制表达式不会被评估。
#define TYPE(x) _Generic((x), \ int: "int type.", \ default: "unknown type." \ ) ... int i = 3; printf("%s\n", TYPE(i = 5)); //这里只判断表达式i=5的类型,但不会给i赋值。 printf("i = %d\n", i); //输出i = 3,i的值保持不变。
如果泛型选择中某个泛型关联的类型与控制表达式的类型兼容,则泛型选择的结果表达式(result expression)是该泛型关联中的表达式;否则泛型选择的结果表达式是default泛型关联中的表达式。泛型选择中任何其它泛型关联中的表达式都不会被评估。
#define FUNC(x) _Generic((x), \ signed: --x, \ unsigned: ++x, \ default: x \ ) ... signed a = 3; unsigned b = 5; printf("a = %d\n", FUNC(a)); //输出a = 2。 printf("b = %u\n", FUNC(b)); //输出b = 6。
泛型选择的类型和值与其结果表达式相同。如果结果表达式分别是左值、函数指示符或者void类型表达式,那么泛型选择就是左值、函数指示符或者void类型表达式。