Block Scoped Variables不算redefinition

-- TOC --

从最早的C89开始,C语言就有一个特性,即在一个独立的block范围内,可以申明与block外同名的变量,此变量独立,不与block外的冲突。示例如下:

#include <stdio.h>


int main(void) {
    int a = 1;
    {
        int a = 2;
        printf("inside a = %d\n", a);
    }
    printf("outside a = %d\n", a);
    return 0;
}

输出:

inside a = 2
outside a = 1

当一个独立的block范围需要重复执行的时候,就出现了(正常的)重复定义。请看下面代码:

#include <stdio.h>
#include <unistd.h>


int main(void) {
    int a = 0;
    while (1) {
        int a = 1;  // !!
        a += 1;
        printf("%d %p\n", a, &a);
        sleep(1);
    }
    return 0;
}

int a = 1在循环中不断地重复,其实,这种情况,不是redefinition!。以上代码可以正常编译执行:

$ gcc -Wall -Wextra test.c -o test
$ ./test
2 0x7fff13df446c
2 0x7fff13df446c
2 0x7fff13df446c

编译正常,变量a的地址在循环过程中保持不变,应该就不存在影响效率的问题了,但每次都会被重新赋值为1。

印象中,C语言是从C99开始,允许函数中的变量可以不在函数开始的位置统一申明和定义。这就给上述代码结构(我很喜欢这种结构,可随时根据代码的局部需要定义变量,可读性也更好,因为相关的代码可以尽可能放在一起)提供了更多的可行性。但独立block范围内的同名变量的相互独立,这个feature,是C89就开始有的。

下面这种情况,也属于在独立范围内定义变量:

#include <stdio.h>
#include <unistd.h>


int main(void) {
    for (int i=0; i<4; ++i)
        printf("%d", i);
    for (int i=0; i<4; ++i)  // int declare is must
        printf("%d", i);
    printf("\n");
    return 0;
}

每个for loop中的变量i,都属于独立范围内定义的,第2个for里的i,如果去掉int申明,编译会报错,提示i未定义。

C++中的对象,也可以在独立范围内(重复)定义:

默念咒语:变量就是有名称的对象!...

#include <string>
#include <iostream>
#include <unistd.h>
using namespace std;


struct xyz {
    xyz() {
        cout << "..1..\n";
    }
    ~xyz() {
        cout << "..2..\n";
    }
};


int main(void) {
    while(1){
        xyz x{};
        sleep(1);
    }
    return 0;
}

以上代码输出:

..1..
..2..
..1..
..2..
..1..
..2..
...

通过打印可以看到,当独立block范围结束的时候,对象会被销毁,然后再进入独立block范围时,再被重建。

代码写成下面这样,也是OK的,对象会被正常销毁,然后重新创建:

#include <string>
#include <iostream>
#include <unistd.h>
using namespace std;


struct xyz {
    xyz() {
        cout << "..1..\n";
    }
    ~xyz() {
        cout << "..2..\n";
    }
};


int main(void) {
    while(1){
        xyz x{};
        if (true)
            sleep(1);
            continue;
        sleep(1);
    }
    return 0;
}

编译器能够判断出,当continue时,这个独立范围的一次迭代就执行结束了,开始下一个迭代。

C++支持在if语句和switch语句中申明对象

请看代码:

#include <stdio.h>


int main(void) {
    // redefinition error
    //int i=0;
    //int i=1;

    if (int i=0; i!=0) {
        // scope of zero i
        printf("i is zero\n");
    }
    else if (int i=1; i==1) {
        // scope of one i
        printf("i is one\n");
    }

    return 0;
}

这段代码,gcc不能编译,但g++就可以正常编译。

据教材上说,这个用法与C++的Structured Binding结合起来,代码看起来非常nice!

下面是switch语句的测试:

#include <stdio.h>

int main(void) {
    switch (int i=9; i) {
        case 1:
            printf("no..\n");
            break;
        case 9:
            printf("yes..\n");
            break;
    }
    return 0;
}

只有g++能编译!

本文链接:https://cs.pynote.net/sf/c/202210241/

-- EOF --

-- MORE --