C++和C标准中的哪些规则使得从其他静态对象初始化静态对象在C++中有效,但在C中无效

iyzzxitl  于 2023-05-02  发布在  其他
关注(0)|答案(3)|浏览(139)

为什么下面的代码编译成C++没有问题,但C编译器却抱怨初始化器不是编译时常量?

int x = 2;
int y = 1;
    
int a[2] = {x, y};

#include <stdio.h>

int main()
{
    printf("Hello world\n");
    return 0;
}
wxclj1h5

wxclj1h51#

从C11标准(6.7.9初始化)
4具有静态或线程存储期限的对象的初始化器中的所有表达式都必须是常量表达式或字符串文字。
在C中,这些声明

int x = 2;
int y = 1;

不提供常量表达式。即使你会写

const int x = 2;
const int y = 1;

然后它们也不提供允许用作具有静态存储持续时间的对象的初始化器的编译时常数表达式。.
从C11标准(6.6常量表达式)
7初始化器中的常量表达式允许有更大的自由度。这样的常量表达式应该是或评估为以下之一:

  • 算术常数表达式,
  • 空指针常数,
  • 地址常数,或
  • 完整对象类型的地址常量加上或减去整数常量表达式。

    8 * 算术常量表达式 * 必须具有算术类型,并且只能具有整数常量、浮点常量、枚举常量、字符常量和sizeof表达式的操作数。算术常数表达式中的强制转换运算符只能将算术类型转换为算术类型,除非作为结果为整数常数的sizeof运算符的操作数的一部分。
    如果你的编译器支持C23标准,那么你可以写
constexpr int x = 2;
constexpr int y = 1;

int a[2] = { x, y };

在C23中,标识符xy被称为 named constantsnamed constants 可以用作具有静态存储持续时间的对象的初始化器。
在 C++ 中,对具有静态存储期的对象的一种初始化

int x = 2;
int y = 1;

int a[2] = { x, y };

称为动态初始化,并在运行时发生。

a7qyws3x

a7qyws3x2#

在C中,静态存储持续时间对象(如全局变量a)必须用常量表达式初始化,而xy不是(在C或C中)。
在C
中,这样的对象可以用任何表达式初始化,它们也可以作为自动存储持续时间变量初始化。然而,对于全局变量,初始化可能发生在运行时,通常在输入main之前,并且主要以未指定的顺序进行。因此,如果可能的话,通常应该避免使用像这样的非constexpr全局变量,或者需要特别注意以正确的顺序初始化依赖项。C在运行时不做任何动态初始化。

gopyfrb3

gopyfrb33#

这个表达式:

int a[2] = {x, y};

需要运行时代码来计算xy的值,并且在C中不允许在函数外部运行代码,但在C中是允许的。
下面是C
代码:

#include <iostream>

class test {
private:
    int a;
    int b;
public:
    abc() {
        cin >> a;
        cin >> b;
    }
};

test x;

int main()
{
    return 0;
}

文件作用域对象x具有带构造函数的类类型。这意味着必须在调用main之前对其进行初始化,并且初始化需要运行代码,因此这需要一种机制来运行main函数之外的代码。
相比之下,C没有在函数之外运行代码的核心需求,所以它从未被引入。因此,C中任何静态对象的初始化都需要在编译时修复初始化器。
当C++从C创建时,添加在main之外运行代码的能力成为核心语言运行所必需的。

相关问题