左值与右值的区别
1.标准整数类型常见存储空间大小和取值范围 (参考《C语言核心技术》, p33)
类型 | 存储空间大小 | 最小值 | 最大值 |
---|---|---|---|
char | 与signed char 和unsigned char 相同 | * | * |
unsigned char | 1个字节 | 0 | 255 |
signed char | 1个字节 | -128 | 127 |
int | 2个字节 or 4个字节 | -32 768 or -2147 483 648 | 32 767 or 2147 483 647 |
unsigned int | 2个字节 or 4个字节 | 0 | 65 535 or 4 294 967 295 |
short | 2个字节 | -32 768 | 32767 |
unsigned short | 2个字节 | 0 | 65 535 |
long | 4个字节 | -2 147 483 648 | 2 147 483 647 |
unsigned long | 4个字节 | 0 | 4 294 967 295 |
long long(C 99) | 8个字节 | -9 223 372 036 854 775 808 | 9 223 372 036 854 775 807 |
unsigned long long(C 99) | 8个字节 | 0 | 18 446 744 073 709 551 615 |
2.左值(lvalue, l最好理解成“locater”,定位器)与右值(rvalue) (参考《C语言核心技术》p71-p72)
在下列表达式选项中,( C)是正确的。
-
A.++(a++)
-
B.a++b
-
C.a+++b
-
D.a++++b
该题解析(analyze):
A选项:a++(右值)通过临时量返回的是一个常量而不是一个对象,因此不能使用前缀++对它进行赋值操作
B、D选项:不规范的运算符
C选项正确:由于后缀优先级大于前缀,因此 a+++b = (a++) + b,
关于左值
一个左值表示一个对象,它可以出现在赋值运算符(assignment operator)的左边,例如“左表达式=右表达式”。那些表示一个值但不指明一个对象的,被类似地成为右值。右值是可以出现在赋值运算符右边而不是左边的表达式,例如,常量和 算术表达式
从一个左值中必定可以解析出对应对象的地址,除非该对象是位字段 (bit-filed) 或者被声明为寄存器存储类。生成左值的运算符包括下标(subscript) 运算符 [] 和间接( indirection) 运算符.
注意:指针和数组表达式可能是左值
表达式 | 是左值吗 |
---|---|
array[1] | yes,一个数组元素是一个具有位置的对象 |
&array[1] | no,此对象的位置,不是一个具有位置的对象 |
ptr | yes,此指针变量是一个具有位置的对象 |
*ptr | yes,指针所指的地方是一个具有位置的对象 |
ptr + 1 | no,加法运算产生了一个新的地址值,但不是一个对象 |
*ptr + 1 | no,此加法运算产生了一个新的算术值,但不是一个对象 |
对象可以被声明为常量。在这种情况下,该对象就不能位于赋值运算的左边,尽管它是一个左值,如下例所示:
int a = 1;
const int b = 2, *ptr = &a;
b = 20; //错误:b被声明为了const int
*ptr = 10; //错误:ptr被声明为指向const int 的指针
analyze:
表达式a、b、ptr和*ptr都是左值,但是b和 *ptr是常量左值,因为ptr被声明为指向 const int 的指针,不能使用它修改它所指向的对象。
赋值运算左边的操作数,以及任何自增或自减运算符(++or–)的操作数,不仅应该是左值,还应该是可修改的左值。可修改的左值,其类型不应该被声明为限定符const,并且可修改的左值不能是数组类型。如果可以修改的左值所表达的对象是结构或联合类型,那么它的元素都不可以被声明(不管是直接的还是间接的)为其有限定符const的类型。