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

表达式(九)

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运算符的操作数类型是charunsigned 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。