当前位置: C语言 -- 基础 -- 表达式

表达式(二)

二、主表达式

主表达式(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};,这里whiteblack是常量表达式,而不是标识符表达式。

字符串字面量主表达式是左值,其类型与编码前缀有关,例如:U"中国"类型是char32_t *类型、L"中国"类型是wchar_t *类型。


括号表达式是主表达式;其类型、值和语义与非括号表达式(unparenthesized expression)相同,例如:5(5),值都是5,类型都是int类型。如果非括号表达式分别是左值、函数指示符或者void类型表达式,那么括号表达式就是左值、函数指示符或者void类型表达式。括号表达式归类为主表达式,保证了括号运算符的优先级高于其它运算符。


泛型选择的语法格式如下所示:

_Generic(assignment-expression , generic-assoc-list)

其中_GenericC语言关键词,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类型表达式。