重学C++ (三) 表达式(含sizeof的使用细节)

本文详细介绍了C++中的表达式,包括求余操作符的适用类型、逻辑运算符的短路求值、关系操作符的使用限制、位操作符的最佳实践、移位操作的规则、赋值操作的右结合性、自增自减操作符的前后置区别、sizeof操作符的工作原理及其在数组、联合体、结构体、动态内存、字符串和位域上的应用。此外,还讨论了逗号表达式和指针删除的注意事项。
摘要由CSDN通过智能技术生成

第五章 表达式

1.求余操作符的操作数只能为整型(包括bool,char,short,int,long类型以及对应的unsigned类型);

2.逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算右操作。它们的求值策略为“短路求值”——只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数;

3.不能串接使用关系操作符,因为关系操作符返回bool类型的结果;(如i < j < k 应写成 i < j && j < k)

4.对于位操作符,由于系统不能确保如何处理其操作数的符号位,所以建议使用unsigned整型操作数;

5.移位操作的右操作数不可以是负数,且必须是严格小于左操作数的位数的值,否则,操作效果是未定义的;

6.赋值操作具有右结合性:

int i = j = 520; //ok, j = 520, i = j;

7.谨防混淆 = 与 == :

if (i = 42) //将42赋给i, 此时i非0,if条件成立

if (i == 42) //检查i是否等于42

8.自增,自减操作符:

前置操作返回加1后的值,所以返回对象本身,是左值;

后置操作返回的是右值;

**前置操作的性能比后置操作好: 前置操作只需加1后返回结果即可;而后置操作需要先保存原来的值,以便返回未加1前的值为操作结果(对于整型对象和指针,编译器可优化这项工作,但是对复杂的迭代器类型,可能会产生比较大的性能差异);

9.

cout << *iter++ << endl;
//等价于:
cout << *(iter++) << endl;
//等价于:
cout << *iter << endl;
++iter;

//后自增操作优先于解引用操作,故等价于*(iter++),上例中,iter先自增,然后(iter++)返回的值是自增前的值,故解引用的是自增前的值;

10.sizeof操作符:

a.首先,它是一个操作符,而不是函数;

b.返回类型为size_t,单位是字节;

c.sizeof操作符不能用于函数类型(即函数指针类型,注意与函数返回值区分),不完全类型或位字段(不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型array[]、未知内容的结构或联合类型、void类型等);

d.对函数调用使用sizeof,在编译阶段会被函数返回值的类型取代(注意,并不执行函数);

e.**sizeof并不计算表达式的值,它的内容(即括号里的部分)将会被替换成类型——计算结果的类型,即返回的是表达式的计算结果的类型大小:

char ch = 1;
int num = 1;
int n1 = sizeof(ch+num);
int n2 = sizeof(ch = ch+num);

/* 结果:
 * ch = 1;
 * n1 = 4;
 * n2 = 1;
 * 解析:
 * ch+num的类型为int,故n1 = sizeof(int) = 4;
 * ch = ch+num的类型为char,故n2 = 1;
 * 而sizeof并不对表达式求值,所以ch的值不变;
 * /

f.当操作数具有数组类型时,其结果是数组的总字节数;

g.当操作数是联合类型时,sizeof是其最大字节成员的字节数;

h.当操作数是结构类型时,sizeof并不等于成员类型的总字节数,因为结构体存在成员对齐,所以可能会有字节填充;
(简单的介绍:
1.结构体大小等于结构体内最大成员大小的整数倍;
2.结构体内成员的首地址相对于结构体首地址的【偏移量是其类型大小的整数倍】,比如double型成员的相对于结构体的偏移量应该是8的倍数;
3.为满足以上规则,编译器会在结构体成员之后进行字节填充。
**因此在结构体成员的顺序安排上需要仔细设计,以节省内存。

i.不能对void进行sizeof操作,但可以对void*进行sizeof操作(4byte);

j.sizeof能求静态分配内存的数组长度(注意char数组最后的’\0’);
注意形参数组:

void fun(int array[10])
{
    int n = sizeof(array);
}

此处n的值为4,因为此处的array被转换成一个int类型的指针(因此在函数间传递数组时,最好增加一个size参数);

k. sizeof不能求得动态分配的内存大小!

int *a = new int[10];
int n = sizeof(a);

此处n为4,因为a是指针!

l. string是C++类型的字符串,是一个类,所以sizeof(s)表示的并不是字符串的长度,而是类string的大小;

m. sizeof不能用于求结构体的位域成员的大小,但是可以求得包含位域成员的结构体的大小:
位域:类型大小都是以字节为基本单位的,1byte等于8bit。char类型为1byte,即8bit,所以可以定义2^8 = 256个数。然而sizeof(bool) = 1,而bool只表示true和false两个数,本来只需要1bit但是却占用了8bit。
通过位域可对内存进行精打细算,简单来说,在结构体成员变量后面跟一个冒号+一个整数,就代表位域:

struct A
{
    bool b:1;
    char ch1:4;
    char ch2:4;
}item;

以上b,ch1,ch2即位域成员,使得b只占用1个bit,ch1,ch2各占用4bit。
注意,位域变量只能在结构体,类,union中使用。

11.逗号表达式的结果是其最右边表达式的值;

12.

int *pi = new int; //没有初始化
int *pi = new int(); //初始化为0

13.对零值指针的删除是合法的,但是并没有意义;

14.一旦删除了指针所指向的对象,应立即将指针置0,在使用指针前进行检查,以免误用;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值