位运算

作者: geaus | 来源:发表于2016-05-05 10:28 被阅读0次
    printf("%f", 5);
    

    上面语句打出的结果为0.000000。原因是printf根据%f会认为参数是double型,因此从栈中读8个字节。而5是int型,内存访问越界,发生不可预料的情况,处理时打印0。

    //结构体位制
    struct a{
        int x : 1;      //这种语法是指定x的bit位数,所以x只有1位
        int y : 2;
        int z : 33;     //z指定33位,但因为是int只有32位,所以报错
    }
    

    下面代码哪个等同于int i=(int) p; (p类型为char *)?

    A int i =  dynamic_cast<int>(p)
    B int i =  static_cast<int>(p)
    C int i = const_cast<int>(p)
    D int i=reinterpret_cast<int>(p)
    

    选D,dynamic_cast用于父类子类间的指针类型转换,static,const的功能也用于这,只有reinterpret_cast(不改变原数据的值),这里是将指针p的值(某地址)按int赋值给i。

    static_cast, const_cast, dynamic_cast, reinterpret_cast
    static_cast用于类型转换,如将int转换为double以便让包含int的表达式产生浮点数值的结果。

    static_cast<double>(firstNumber)/secondNumber
    

    不能用于将double转为指针或者struct转int,不能去除const属性。
    const_cast最普通的用途就是去掉对象的const属性。

    class B{
    public:
        int m_iNum;
    };
    int main(){
        B b0;
        b0.m_iNum=100;
        const B b1=b0;
        cout<<b0.m_iNum<<" "<<b1.m_iNum<<endl;
        const_cast<B&>(b1).m_iNum=200;
        cout<<b0.m_iNum<<" "<<b1.m_iNum<<endl;
        return 0;
    }
    

    static_cast和reinterpret_cast操作修改了操作数类型。static_cast编译时使用类型信息执行转换,相对安全。reinterpret_cast仅仅是重新解释对象的比特模型,没有进行二进制转换,比较危险。

    int n=9;
    static_cast<double>(n);  //这里会为n补位
    reinterpret_cast<double>(n);    //不会补位
    

    dynamic_cast使用需要注意

    1. dynamic_cast是在运行时检查,用于进行安全的向下转换。如果源和目标类型没有继承和被继承关系,编译器会报错;必须判断返回值是否为NULL来确认转换是否成功。
    2. dynamic_cast是4个转换中唯一的RTTI操作符,提供运行时类型检查。
    3. dynamic_cast不是强制转换,而是咨询性质的转换,不能转换的话返回NULL。

    对于类中的成员函数,如果不涉及类成员变量,则即使该类的指针为NULL时,也可以通过该指针调用该成员函数。

    class B{
    public:
        void disp(){ cout<<"hello world"<<endl; }
    };
    int main(){
        B *b0=NULL;
        b0->disp();
        return 0;
    }
    

    但如果该类继承了父类,且该方法为虚函数,则调用会出错,因为调用虚方法要求对象有一个虚函数表指针。

    class A{
    public:
        virtual void disp(){ cout<<"hello A"<<endl; }
    };
    class B : public A{
    public:
        virtual void disp(){ cout<<"hello B"<<endl; }
    };
    int main(){
        B *b0=NULL;
        b0->disp();
        return 0;
    }
    

    建立一个联合体,由char和int类型组成

    union{
        unsigned char a;
        unsigned int i;
    }u;
    u.i=0xf0f1f2f3;
    cout<<hex<<u.i<<endl;       //输出f0f1f2f3
    cout<<hex<<u.a<<endl;       //输出f3
    

    说明内存中数据低位字节存入低地址,高位字节存入高地址,数据的地址采用它的低地址表示。
    当一个变量的值可能会在编译器的控制或监测之外被改变时,那么它应该声明为volatile。因此编译器执行的例行优化行为不能应用在该指定为volatile变量上。这样,优化器在用到这个变量时都必须每次的重新读取这个变量的值,而不是使用保存在寄存器的备份。
    可以建立const volatile变量,这样这个变量不能被程序员改变,但可以通过外面的工具改变。
    const意味着“只读”。
    下面的函数有什么错误?

    int square(volatile int *ptr){ return *ptr * *ptr; }
    

    上面的代码本意是返回ptr的平方,但由于执行时ptr可能会改变,类似于下面的代码

    int square(volatile int *ptr){
        int a=*ptr;
        int b=*ptr;
        return a*b;
    }
    

    正确的应该如下

    int square(volatile int *ptr){
        int a=*ptr;
        return a*a;
    }
    

    小尾字节序和大尾字节序
    前者是指CPU对操作数的存放方式是从低字节到高字节即低位字节存放在低地址,高位字节存放在高地址。后者则相反,低地址存高位字节,高地址存低位字节。
    或者解释为,沿着地址向上的方向,小尾先存低后存高;大尾先存高后存底。

    //存储0x1234
    //小尾
    0x4000 0x34
    0x4001 0x12
    //大尾
    0x4000 0x12
    0x4001 0x34
    

    static关键字的作用:

    staic_Image.png

    相关文章

      网友评论

          本文标题:位运算

          本文链接:https://www.haomeiwen.com/subject/mikdrttx.html