zoukankan      html  css  js  c++  java
  • C++ Primer 第四版读书笔记(四)之表达式

    表达式由一个或多个操作数通过操作符组合而成。最简单的表达式仅包含一个字面值常量或变量。较复杂的表达式则由操作符以及一个或多个操作数构成。

    每个表达式都会产生一个结果。如果表达式中没有操作符,则其结果就是操作数本身的值。当一个对象用在需要使用其值的地方,则计算该对象的值。

    操作符的含义——该操作符执行什么操作以及操作结果的类型——取决于操作数的类型。

    C++提供了一元操作符和二元操作符两种操作符。作用在一个操作数上的操作符称为一元操作符。如曲地址符(&)和解引用操作符(*);而二元操作符则作用于两个操作数上,如加法操作符(+)和减法操作符(-)。

    一、算术操作符

    当只有一个操作数为负数时,求模操作结果值的符号可依据分子(被除数)或分母(除数)的符号而定。如果求模的结果随分子的符号,则除出来的值想零一侧取整;如果求模与分母的的符号匹配,则除出来的值向负无穷一侧取整。

    二、关系操作符和逻辑操作符

    关系操作符和逻辑操作符
    操作符 功能
    ! 逻辑非
    <
    <=
    >
    >=
    小于
    小于等于
    大于
    大于等于
    ==
    !=
    等于
    不等
    && 逻辑与
    || 逻辑或

    2.1 逻辑与、逻辑或操作符

    仅当逻辑与(&&)操作符的两个操作数都为true,其结果才得true。

    对于逻辑或(||)操作符,只要两个操作数之一为true,它的值就为true。

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

    2.2 不应该串接使用关系操作符

    三、位操作符

    位操作符使用整型的操作数。位操作符将其整型操作数视为二进制位的集合,为每一位提供检验和设置的功能。

    位操作符
    操作符 功能
    ~ 位求反
    <<
    >>
    左移
    右移
    & 位与
    ^ 位异或
    | 位或

    位操作符操纵的整数的类型可以是有符号的也可以是无符号的。如果 操作数为负数,则位操作符如何处理其操作数的符号位依赖于机器。于是它们的应用可能不同:在一个应用环境中实现的程序可能无法用于另外一应用环境。

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

    左移操作符(<<)在右边插入0以补充空位。对于右移操作符(>>),如果其操作数是无符号位,则从左边开始插入0;如果操作数是有符号位,则插入符号位的副本或者0值,如何选择需依据具体的实现而定。移位操作的右操作数不可以是负数,而且必须是严格小于左操作数位数的值。否则,操作的效果未定义。

    3.1 bitset对象或整型值的使用

    3.2 将移位操作符用于IO

    四、 赋值操作符

    复制操作数的左操作数必须是非const的左值。

    五、自增和自减操作符

    六、sizeof操作符

    sizeof操作符的作用是返回一个对象或类型名的长度,返回值的类型为size_t,长度的单位是字节。sizeof表达式的结果时编译时常量,该操作符有以下三种语法形式:

    sizeof(type name);

    sizeof ( expr);

    sizeof expr;

    将sizeof应用在表达式expr上,将获得该表达式的结果的类型长度。

    将sizeof用于expr时,并没有计算表达式expr的值。特别是在sizeof *p中,指针p可以持有一个无效地址,因为不需要对p做解引用操作。

    使用sizeof的结果部分地依赖所涉及的类型:

    1、对char类型或值为char类型的的表达式做sizeof操作保证得1;

    2、对引用类型做sizeof操作将返回存放此引用类型对象所需的内存空间的大小。

    3、对指针做sizeof操作将返回存放指针所需的内存的大小;注意,如果要获取该指针所指向对象的大小,则必须对该指针进行解引用。

    4、对数组做sizeof操作等效于将对其元素类型做sizeof操作的结果乘上数组元素的个数。

    七、new和delete表达式

    定义变量时,必须指定其数据类型和名字。而动态创建对象时,只需要指定其数据类型,而不必为该对象命名。取而代之的是,new表达式返回指向新创建对象的指针,我们通过该指针来访问此对象。

    7.1 动态创建对象的初始化

    动态创建对象可用初始化变量的方式实现初始化:

    int i(1024);

    int *pi = new int(1024);

    string s(10, '9');

    string *ps = new string(10. '9');

    C++使用直接初始化语法规则初始化动态创建的对象。如果提供了初值,new表达式分配到所需要的内存后,用给定的初值初始化该内存空间。

    7.2 动态创建对象的默认初始化

    如果不提供显示初始化,动态创建的对象与函数内定义的变量初始化方式相同。对于类类型的对象,用该类的默认构造函数初始化;而内置类型的对象则无初始化。

    7.3 耗尽内存

    如果new表达式无法获取需要的内存空间,系统将抛出名为bad_alloc的异常。

    7.4 撤销动态创建的对象

    动态创建的对象用完后,程序员必须显示地将该对象占用的内存返回给自由存储区。C++提供了delete表达式释放指针所指向的地址空间。

    7.5 零值指针的删除

    如果指针的值为0.则在其上做delete操作是合法的,但这样没有任何意义:

    int *ip = 0;

    delete ip;

    C++保证:删除0值的指针是安全的。

    7.6 在delete之后,重设指针的值

    删除指针后,该指针变成悬垂指针。悬垂指针指向曾经存放对象的内存,但该对象已经不再存在了。悬垂指针往往导致程序错误,而且很难检测出来。

    一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象。

    7.7 const对象的动态分配和回收

    const int *pci = new const int(1024);

    与其他常量一样,动态创建const对象必须在创建时初始化,并且一经初始化,其值就不能在修改。

    警告:动态内存的管理容易出错

    下面三种常见的程序错误都与动态内存分配相关:

    (1)、删除(delete)指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间后,耗尽了所有的内存空间,内存泄漏才会显露出来。

    (2)、读写已删除的对象。如果删除指针所指向的对象之后,将指针置为0值,则比较容易检测出这类错误。

    (3)、对同一个内存空间使用两次delete表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做delete运算,将该对象的内存空间返还非自由存储区,然后接着delete第二个指针,此时则自由存储区可能会被破坏。

    7.8  删除const对象

    delete pci;

    即使delete表达式的操作数是指向int型const对象的指针,该语句同样有效回收pci所指向的内容。

    八、类型转换

    表达式是否合法取决于操作数的类型,而且合法的表达式其含义也是由操作数类型决定。

    如果这两个类型之间可以相互转换,则称这两个类型相关。

    C++并不是把两个不同类型的值直接加在一起,而是提供了一组转换规则,以便在执行算术操作之前,将两个操作数转换为同一种数据类型。这些转换规则由编译器自动执行,无需程序员介入。因此,他们也被称为隐式类型转换。

    8.1  何时发生隐式类型转换

    编译器在必要时将类型转换规则应用到内置类型和类类型的对象上。在下列 情况下,将发生隐式类型转换:

    1、在混合类型表达式中,其操作数被转换为相同的类型:

    int ival;

    double dval;

    ival >= dval;//ival converted to double

    2、用作条件的表达式被转换为bool类型:

    3、用一表达式初始化某个变量,或将一表达式赋值给某个变量,则该表达式被转换为该变量的类型

    8.2 算术转换

    8.2.1 有符号与无符号类型之间的转换

    若表达式中使用了无符号数值,所定义的转换规则需保护操作数的精度。unsigned 操作数的转换依赖于机器中整型的相对大小,因此,这类转换本质上依赖于机器。

    8.3 其他隐式转换

    8.3.1 指针转换

    在使用数组时,大多数情况下数组都会自动转换为指向第一个元素的指针:

    int ia[10];

    int *ip = ia;

    不将数组转换为指针的例外情况有:数组用作取地址(&)操作符的操作数或sizeof操作符的操作数时,或用数组对数组的引用进行初始化时,不会将数组转换为指针。

    C++还提供了另外两种指针转换:指向任意数据类型的指针都可转换为void*类型;整型值常量0可转换为任意指针类型。

    8.3.2 转换为bool类型

    8.3.3 算术类型与bool类型的转换

    8.3.4 转换与枚举类型

    C++自动将枚举类型的对象或枚举成员转换为整型,其转换结果可用于任何要求使用整数值的地方。

    九、显示转换

    显示转换称为强制类型转换(cast),包括以下列名字命名的强制类型转换操作符:

    static_cast、dynamic_cast、const_cast和reinterpret_cast。

    9.1 何时需要强制类型转换

    因为要覆盖通常的标准转换,所以需显示使用强制类型转换。

    显示使用强制类型转换的另一个原因是:可能存在多种转换时,需要选择一种特定的类型转换。

    9.2 命名的强制类型转换


  • 相关阅读:
    应用安全
    协议
    应用安全
    数据库-redis
    应用安全
    WEB中间件--Jboss未授权访问,加固,绕过
    WEB中间件--tomcat爆破,burp和python脚本,getshell,war包
    WEB中间件漏洞--IIS
    文件包含漏洞(RFI)
    sql注入记录------类型转换错误---convert()函数,一句话图片马制作
  • 原文地址:https://www.cnblogs.com/SunkingYang/p/11049236.html
Copyright © 2011-2022 走看看