2019年4月22日
4.10 逗号操作符
逗号表达式是一系列由逗号分开的表达式。这些表达式从左向右计算。逗号表达式的结果是最右边表达式。
在下面例子中,条件操作符的每边都是逗号表达式。第一个逗号表达式的值是ix,而第二个表达式的值是0。
int main()
{
//examplies of a comma expression
//ia , sz ,and index are defined elsewhere
int ival = (ia != 0)
? ix= get_value(),ia[index] = ix
: ia = new int[sz] , ia[index] = 0;
}
4.11 位操作符
位操作符把操作数解释成有序的集合,这些位可能是独立的,也可能组成域(field)。每个位可以含有0(off)或1(on)。位操作符允许程序员设置或测试独立的位或位域。如果一个对象被用作一组位或位域的离散集合,那么这样的对象称为位向量(bitvector)。位向量是一种用来记录一组项目或条件的是/否信息[flag]的紧缩方法。例如,在编译器中,类型声明的限定修饰符(qualifier),如const和volatile,有时就被存储在位向量中。iostream库用位向量表示格式状态,例如输出的整数是以十进制、十六进制,还是八进制显示。
4.12 bitset操作
test(pos) pos位是否为1?
any() 任意位是否为1?
none() 是否没有位为1?
count() 值是1的位的个数
size() 位元素的个数
[pos] 访问pos位
flip() 翻转所有的位
flip(pos) 翻转pos位
set() 将所有位置1
set(pos) 将pos位置1
reset 将所有位置0
reset(pos)将pos位置0
用整数类型表示位向量的问题在于,使用位操作符来设置、复位和测试单独的位,层次也比较低,也比较复杂。例如,用整值类型将第27位设置为1,我们可以这些写: quiz1 |= 1<<27;
而用bitset来做,我们可以这样写: quizl[27] = 1;
或者 quiz1.set(27);
4.13优先级
操作符优先级是指复合表达式中操作符计算的顺序。例如,在下面的定义中,最终被赋值给ival的是什么?
int ival = 6+3*4/2+2 //14
用括号把一些子表达式起来,可以改变优先级。再复合表达式计算中,第一个动作是计算所有括号中的字表达,在用计算的结果代替每个子表达式,然后计算。里边的括号比外面的括号先计算。
4.14类型转换
4.14.1隐式类型转换
c++定义了一组内置类型对象之间的标准转换,在必要时候他们被编译器隐式地应用达到对象上。隐式类型转换在下列这些典型情况下:
·在混合类型的算术表达式中。在这种情况下,最宽的数据类型称为目标转换类型。这也称为算术转换(arithmetic conversion)。
·用一种类型表达式给另一种类型的对象。在这种情况下,目标转换类型是被赋值对象的类型。
int *pi = 0;
ival = dval;
·把一个表达式传递给一个函数调用,表达式的类型与形式参数的类型不相同。在这种情况下,目标转换类型是形式参数的类型。
extern double sqrt(double);
cout<<”The square root of 2 if”
<<sqrt(2)<<endl;
·从一个函数返回一个表达式,表达式的类型与返回类型不相同。在这种情况下,目标转换类型是函数的返回类型。
double difference(int ival1 , int ival2)
{
//返回值被提升为double类型
return ival1 – ival2;
}
4.12.2 算术转换
算术转换保证了二元操作符(如加法或乘法)的两个操作数被提升为共同的类型,然后在用它表示结果的类型。两个通用的知道原则如下:
- 为防止精度损失,如果必要的话,类型总是被提升为较宽的类型。
- 所有含有小于整型的有序类型的算术表达式。在计算之前,其类型都会都会被转换成整型。
规定的定义如下面所述,这些规则定义了一个类型转换层次结构。(我们从最宽的类型long double开始。)
如果一个操作数的类型是long double,那么另一个操作数无论是什么类型,都将被转换成long double。
如果两个操作数都不是long double型,那么当其中一个操作数的类型是double型,则另一个就将被转换成double型。例如:
int ival;
float fval;
doule davl;
//在加法之前,fval和ival都被转换成double
dval + fval + ival;
类似地,如果两个操作数都不是double型,而其中一个操作数是float型,则另一个被转换成float型。例如:
char cval;
int ival;
float fval;
//在计算加法前,ival和cval 都被转换成double
cval + fval + ival;
否则,因为两个操作数都不是三种浮点类型之一,它们一定是某种整值类型。在确定共同目标提升类型之前,编译器将在所有小于int 的整值类型上施加一个被称为整值提升(integral promotion)的过程。
在进行整值提升时候,类型char、signed char 、unsigned char 和short int 都被提升为类型int 。
如果机器上的m型足够表示所有的unsinned shoft型的值,则unsigned short int 也被转换成int。否则,它会被提升为unsigned int 。
wchar_t 和枚举类型被提升为能够表示其底层类型(underlying type)所有值的最小整数类型。例如,已知如下枚举类型:
enum status{bad,ok};
相关联的值是0和1。这两个值可以(但不必须)存放在char类型中。当这些值实际上被作为char类型存储时候,char代表了枚举的底层类型。然后,status的整值提升姜它的底层类型转换为int。
尽管算术转换的这些规则可能给你的困惑多于启发,但是,一般的思想是,尽可能地保留多类型表达式中涉及到的值的精度。者正是通过“把不同类型提升到当前出现的最宽的类型”来实现的。