表达式(九)
3、一元算术运算符
本节讨论的一元算术运算符(unary arithmetic operators)仅包括:+(一元加运算符)、-(一元减运算符)。
一元加运算符(+)的操作数应具有算术类型,运算结果值是操作数整数提升后的值,类型是操作数整数提升后的类型。
#define TYPE(x) _Generic((x), \ signed char : "signed char type", \ int : "int type", \ default : "unknown type" \ ) ... signed char ch = 'A'; printf("%d\n", +ch); //输出65。 printf("%s\n", TYPE(+ch)); //输出int type。
一元减运算符(-)的操作数应具有算术类型,运算结果值是操作数整数提升后的相反数,类型是操作数整数提升后的类型。
#define TYPE(x) _Generic((x), \ signed char : "signed char type", \ int : "int type", \ default : "unknown type" \ ) ... signed char ch = 'A'; printf("%d\n", -ch); //输出-65。 printf("%s\n", TYPE(-ch)); //输出int type。
4、sizeof运算符和alignof运算符
sizeof运算符的表达式具有以下两种语法格式:
sizeof unary-expression
sizeof (type-name)
其中unary-expression是一元表达式,但不能是函数类型表达式、不完整类型表达式或者表示位字段(bit-field)成员的表达式;type-name是类型名,但不能是函数类型,也不能是不完整类型。
sizeof运算符的操作数可以是表达式,也可以是类型名;运算结果是以字节为单位的操作数的大小(操作数的大小由操作数的类型决定。);运算结果是整数,类型是size_t类型。
#define TYPE(x) _Generic((x), \ size_t : "size_t type", \ int : "int type", \ default : "unknown type" \ ) ... int i = 5; printf("%u\n", sizeof i); //输出4。 printf("%u\n", sizeof(int)); //输出4。 printf("%s\n", TYPE(sizeof i)); //输出size_t type。 printf("%s\n", TYPE(sizeof(int))); //输出size_t type。
如果sizeof运算符的操作数类型是变长数组类型(variable length array type),操作数会被评估;否则sizeof运算符的操作数不会被评估。
size_t func(unsigned u) { int arr[u+2]; return sizeof arr; } ... int i = 7; printf("%u\n", sizeof i++); //输出4。 printf("%d\n", i); //输出7。 printf("%u\n", func(5)); //输出28。
如果sizeof运算符的操作数类型是char、unsigned char或者signed char类型(以及这些类型的限定版本。),结果为1。如果sizeof运算符的操作数类型是结构类型或者联合类型,结果为该类型对象的总字节数,包括内部填充(internal padding)和尾部填充(trailing padding)。如果sizeof运算符的操作数类型是数组类型,结果为数组的总字节数。如果sizeof运算符的操作数是声明为数组类型或者函数类型的形式参数,结果是转换后指针类型的大小。
struct s{ int i; double d; unsigned u; }; size_t func(int n, int arr[n]) { return sizeof arr; //这里sizeof arr等价于sizeof(int *)。 } ... int arr[5]; printf("%u\n", sizeof(char)); //输出1。 printf("%u\n", sizeof arr); //输出20。 printf("%u\n", sizeof(struct s)); //输出24。 printf("%u\n", func(5,arr)); //输出8。
sizeof运算符有两个重要用途:
①与存储分配器、I/O系统等进行通信;内存分配函数接受以字节为单位的待分配对象的大小,并返回void类型指针。
int *ptr = NULL; ptr = malloc(5*sizeof(int));
②计算数组的元素数量。
char arr[] = "Cease to struggle and you cease to live."; printf("%u\n", sizeof arr/sizeof arr[0]);
alignof运算符的表达式具有以下语法格式:
alignof (type-name)
其中type-name是类型名,但不能是函数类型,也不能是不完整类型。alignof运算符的操作数是类型名,运算结果是类型名指定类型的对齐要求。如果操作数类型是数组类型,运算结果是数组元素的对齐要求。alignof运算符的运算结果是size_t类型的整数常量。
alignof运算符的操作数不会被评估。作为非标准扩展,有些C编译器(例如:GCC)允许alignof运算符的操作数是表达式。
struct s{ int i; double d; unsigned u; }; ... printf("%u\n", alignof(int)); //输出4。 printf("%u\n", alignof(int [5])); //输出4。 printf("%u\n", alignof(double)); //输出8。 printf("%u\n", alignof(struct s)); //输出8。