C++知识点复习


static

static变量只能初始化一次:

#include <cstdio>
#include <iostream>

using namespace std;

void fun(int i) {
    static int value = i;
    printf("%d\n", value);
}

int main() {
    
    fun(0);
    fun(1);
    fun(2);

    return 0;
}

输出为:

0
0
0

因为static变量只初始化一次,static int value = i这句话只执行一次,也就是fun(0)的时候执行。之后这条语句就不再执行。所以value一直为0。

#include <cstdio>
#include <iostream>

using namespace std;

void fun(int i) {
    static int value = i;
    value++;
    printf("%d\n", value);
}

int main() {
    
    fun(0);
    fun(1);
    fun(2);

    return 0;
}

输出:

1
2
3


const

const修饰指针:

const char * p; const 在*之前(等价char const * p) 指向常量,指针所指内容不可改,但指针可指向别处。

char * const p; const 在*之后指针不可改(即不可指向别处),但所指内容可以修改。

const char * const p;指针本身和所指内容都不可改

#include <cstdio>
#include <iostream>

using namespace std;

int main() {
    int value1 = 1, value2 = 2;

    const int * p1 = & value1;
    p1 = & value2;
    // *p1 = 2; // invalid

    int * const p2 = & value1;
    // p2 = & value2; // invalid
    *p2 = 22;

    const int * const p3 = & value1;
    // p3 = & value2; // invalid
    // *p3 = 33; // invalid

    printf("%d %d\n%d %d\n", value1, value2, *p1, *p2);

    return 0;
}

输出:

22 2
2 22

常引用:

常引用可用右值初始化

#include <cstdio>
#include <iostream>

using namespace std;

int main() {
    int value1 = 1;

    int & ref1 = value1;
    const int & ref2 = value1;

    ref1 = 3;
    // ref2 = 4; // invalid

    // int & ref3 = 1; // invalid
    const int & ref4 = 1; // valid

    printf("%d\n%d %d %d\n", value1, ref1, ref2, ref4);

    return 0;
}

输出:

3
3 3 1



volatile

"

volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.

简单地说就是防止 编译器对代码进行优化.比如如下程序:
1
2
3
4
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有 XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入 volatile,则编译器会逐一的进行编译并产生相应的机器代码(产生四条 代码).
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:
1
2
3
4
int  square( volatile  int  *ptr)
{
     return  ((*ptr) * (*ptr));
}
下面是答案:
1). 是的。一个例子是只读的 状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的 指针时。
3). 这段代码是个恶作剧。这段代码的目的是用来返 指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数, 编译器将产生类似下面的代码:
1
2
3
4
5
6
7
int  square( volatile  int  *ptr)
{
     int  a,b;
     a = *ptr;
     b = *ptr;
     return  a*b;
}
由于*ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。结果,这段代码可能返回的不是你所期望的平方值!正确的代码如下:
1
2
3
4
5
6
long  square( volatile  int *ptr)
{
     int  a;
     a = *ptr;
     return  a*a;
}

下面我们来一个个说明。
考虑下面的代码:
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classGadget
{
     public :
         void  Wait()
         {
             while (!flag_)
             {
                 Sleep(1000); //sleeps for 1000milli seconds
             }
         }
         void  Wakeup()
         {
             flag_= true ;
         }
         //...
     private :
         bool  flag_;
};
上面代码中Gadget::Wait的目的是每过一秒钟去检查一下flag_成员 变量,当flag_被另一个线程设为true时,该函数才会返回。至少这是程序作者的意图,然而,这个Wait函数是错误的。
假设 编译器发现Sleep(1000)是调用一个外部的库函数,它不会改变成员 变量flag_,那么编译器就可以断定它可以把flag_缓存在 寄存器中,以后可以访问该寄存器来代替访问较慢的主板上的内存。这对于 单线程代码来说是一个很好的优化,但是在现在这种情况下,它破坏了程序的正确性:当你调用了某个Gadget的Wait函数后,即使另一个线程调用了Wakeup,Wait还是会一直循环下去。这是因为flag_的改变没有反映到缓存它的寄存器中去。 编译器的优化未免有点太……乐观了。
在大多数情况下,把 变量缓存在寄存器中是一个非常有价值的优化方法,如果不用的话很可惜。C和C++给你提供了显式禁用这种缓存优化的机会。如果你声明 变量是使用了volatile 修饰符编译器就不会把这个 变量缓存在 寄存器里——每次访问都将去存取变量在内存中的实际位置。这样你要对Gadget的Wait/Wakeup做的修改就是给flag_加上正确的修饰:
1
2
3
4
5
6
7
class  Gadget
{
     public :
         //...as above...
     private :
         volatile  bool  flag_;
};

"

--摘自百度百科






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值