在C++中,你可以在c.h
中声明一个类C
,它包含static const int var = 3;
的声明和初始化。
class C {
public:
...
static const int var = 3
...
};
字符串
除非您将该变量设置为inline,或者在c.cpp
中显式定义它,
...
const int C::var;
...
型
它是未定义的。
- 那么,即使在不与内存地址相关的事情中使用
var
,就像for循环中的计数器一样,也是未定义的行为吗? - 编译器如何使用未定义变量的值?预处理器宏是否替换了它的值?
- 除了在类声明中使用静态int变量的情况之外,还有其他情况可以声明和初始化但未定义的变量吗?
- 这在C编程语言中会发生吗?
我知道一定有某种机制来实现这一点,因为我见过使用未定义的静态常量变量的C++代码。但我希望引用标准。
2条答案
按热度按时间yqhsw0fo1#
根据[class.static.data]/4第1句,仅当
var
具有const
限定的整数或枚举类型并由 * 常量表达式 * 初始化时,才允许将此静态数据成员结构作为一般规则的例外。根据[basic.def.odr]/10(由[class.static.data]/4第2句重申),需要
var
的定义,如果var
是 * odr-使用 。否则,程序就是IFNDR(格式错误,不需要诊断)。一般来说,如果一个变量是在一个 * discovered statement 之外的 potentially-evaluated expression 中命名的,那么它总是被odr使用的。
但是,因为
var
是const
整型或枚举类型,并且用常量表达式初始化,所以它 * 可用于常量表达式 *(并且不能有可变的子对象),因此即使var
是在可能求值的表达式中命名的,[basic.def.odr]/4.2中的异常也可能适用。如果在表达式中对var
所做的只是立即读取其值(lvalue-to-rvalue conversion),而不是例如:形成对其的指针/引用。因为变量是用常量表达式初始化的,所以编译器可以用给定给var
的编译时常量值替换变量的使用。正如@LanguageLawyer在这个答案下的评论中指出的那样,该标准目前在[intro.object]/1中说 definitions 可以创建对象,但不是说 declarations 通常可以。这是一个问题,因为即使没有
var
的定义,你没有违反ODR,你仍然不会有一个对象,但是左值到右值的转换是根据阅读 object 的值来指定的(或者当ODR异常应用时,根本不依赖于解释)。如果没有定义的行为,程序在计算表达式时仍然会有未定义的行为。然而,这显然是无意的,并且是标准中的缺陷。在[basic.def.odr]/4.3中还有一个小的例外,当变量被直接命名为 discarded-value expression 时,例如当将
var;
作为语句写入时。在这种情况下,编译器既不需要var
的值也不需要var
的地址。这些都与预处理器无关,它在解析实际的C++代码之前专门工作。
这是我认为唯一的例外,你可以有一个初始化声明的变量,而不是在同一时间的变量的定义。它的存在只是因为历史原因,在
constexpr
和inline
可以用于变量以使静态数据成员的值在常量表达式中可用之前。guicsvcw2#
这在C语言中会发生吗?*
在C语言中,如果在头文件中定义了变量
static int var = 3;
,那么包含该头文件的每个C源文件都会有自己的本地副本(如果定义了var
)。没有 * 声明和初始化,但未定义变量 *。请注意,如果编译器被配置为生成有用的警告,则会报告未使用的
static
变量,因此您应该会收到多个警告,除非您在每个源文件中都使用var
。全局
const
定义在C和C++中有细微的不同语义,但这是一个不同的问题。