提问人:Muhammed Elmaghraby 提问时间:5/2/2023 最后编辑:StoryTeller - Unslander MonicaMuhammed Elmaghraby 更新时间:5/2/2023 访问量:158
C++ 和 C 标准中的哪些规则使从其他静态对象初始化静态对象在 C++ 中有效,但在 C 中无效
What rules in the C++ and C standards make initialization of static objects from other static objects valid in C++ but not C
问:
为什么下面的代码编译为 C++ 而没有抱怨,但 C 编译器抱怨初始值设定项不是编译时常量?
int x = 2;
int y = 1;
int a[2] = {x, y};
#include <stdio.h>
int main()
{
printf("Hello world\n");
return 0;
}
答:
在 C 中,静态存储持续时间对象(例如全局变量)必须使用常量表达式进行初始化,这些表达式不是(在 C 或 C++ 中)。a
x
y
在 C++ 中,可以使用任何表达式初始化此类对象,也可以将其初始化为自动存储持续时间变量。但是,对于全局变量,初始化可能在运行时发生,通常在输入之前,并且主要以未指定的顺序进行。因此,如果可能的话,通常应避免使用此类非全局变量,或者需要特别注意以正确的顺序初始化依赖项。C 在运行时不执行任何动态初始化。main
constexpr
从 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 Standard,那么你可以编写
constexpr int x = 2;
constexpr int y = 1;
int a[2] = { x, y };
在C23标识符和命名常量中,命名常量可以用作具有静态存储持续时间的对象的初始值设定项。x
y
在 C++ 中,这种具有静态存储持续时间的对象初始化
int x = 2;
int y = 1;
int a[2] = { x, y };
称为动态初始化,在运行时发生。
评论
enum { x = 2, y = 1 }; int a[2] = { x, y };
x
const int x = 2;
此表达式:
int a[2] = {x, y};
需要运行时代码来计算 和 的值,并且不允许在函数外部运行代码,而在 C++ 中。x
y
给定以下 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
下一个:C++ 范围问题?[复制]
评论
#include <cstdio>