为什么未诊断出在 constexpr 上下文中使用保留的标识符名称?
Why is using a reserved identifier name in constexpr context not diagnosed?
基于以下两条规则:
- 使用以“_”+大写字母开头或包含双下划线的标识符是未定义的行为。
- constexpr 表达式中不允许出现未定义的行为 -> 编译器不应编译。
那为什么编译器不抱怨这个呢?
constexpr int _UB() {return 1;}
int main() {
constexpr int a = _UB();
return a;
}
另外,我看到很多专业的、符合 MISRA 标准的代码似乎违反了这个命名规则,例如参见here:
#ifndef __STM32F732xx_H
#define __STM32F732xx_H
所有这些库都调用 UB 吗?
Undefined behavior is not allowed in constexpr expressions -> compiler should not compile
比这个窄一点;特别是 [expr.const]/5, /5.7:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
- [...]
- /5.7 an operation that would have undefined behavior as specified in [intro] through [cpp];
现在,[intro] 通过 [cpp] 包括:
1 Scope[intro.scope]
2 Normative references[intro.refs]
3 Terms and definitions[intro.defs]
4 General principles[intro]
5 Lexical conventions[lex]
6 Basics[basic]
7 Expressions[expr]
8 Statements[stmt.stmt]
9 Declarations[dcl.dcl]
10 Modules[module]
11 Classes[class]
12 Overloading[over]
13 Templates[temp]
14 Exception handling[except]
15 Preprocessing directives[cpp]
然而,关于全局名称下划线的规则来自[library],特别是[library]中的[reserved.names]/2 and [global.names]/1,“[intro] through [cpp]”没有涵盖。
[reserved.names]/2 If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
[global.names]/1 Certain sets of names and function signatures are always reserved to
the implementation:
- (1.1) Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter ([lex.key]) is reserved
to the implementation for any use.
- (1.2) Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
现在,[lex.name]/3 也包含相同的标识符保留规则
In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
- (3.1) Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the
implementation for any use.
- (3.2) Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
违反[lex.name]/3 是格式错误的,不需要诊断(IFNDR),这与未定义的行为不同;根据上面的 [expr.const]/5.7,一些 UB 应该 实际上被诊断出来(constexpr 上下文)。
根据 [intro] 通过 [cpp] [expr.const]/5.7 对 UB 的限制可以说是有意限制规则以避免构造对于典型的 C++ 实现者来说是 UB 而不是 STL 库实施者,例如[库]中的规则。这也可能是一个措辞缺陷,特别是 [lex.name]/3 的规则仅在 [[library] 中 [reserved.names]/2 的“事后”才从 IFNDR 变为 UB。
因此,这种“种类”的未定义行为 (UB) 可以说不属于使表达式无法成为核心常量表达式的 UB。
拥有遵循这些约定的宏、变量或其他成员不是“未定义的行为”。它完全合法,不同于以数字、控制字符或其他类似内容开头的标识符。
以两 (2) 个下划线开头的标识符,例如
typedef uint32_t __my4ByteInt;
不推荐,因为标准库将此约定用于内部标识符,如果您的成员具有相同的名称,它可能会导致问题。
除此之外,这些标识符是合规的。我不确定 MISRA,但即使在那里,我也相当确定命名约定只是建议,不会由编译器检查,而是由第三方分析工具(如 CodeSonar)检查。
基于以下两条规则:
- 使用以“_”+大写字母开头或包含双下划线的标识符是未定义的行为。
- constexpr 表达式中不允许出现未定义的行为 -> 编译器不应编译。
那为什么编译器不抱怨这个呢?
constexpr int _UB() {return 1;}
int main() {
constexpr int a = _UB();
return a;
}
另外,我看到很多专业的、符合 MISRA 标准的代码似乎违反了这个命名规则,例如参见here:
#ifndef __STM32F732xx_H
#define __STM32F732xx_H
所有这些库都调用 UB 吗?
Undefined behavior is not allowed in constexpr expressions -> compiler should not compile
比这个窄一点;特别是 [expr.const]/5, /5.7:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
- [...]
- /5.7 an operation that would have undefined behavior as specified in [intro] through [cpp];
现在,[intro] 通过 [cpp] 包括:
1 Scope[intro.scope] 2 Normative references[intro.refs] 3 Terms and definitions[intro.defs] 4 General principles[intro] 5 Lexical conventions[lex] 6 Basics[basic] 7 Expressions[expr] 8 Statements[stmt.stmt] 9 Declarations[dcl.dcl] 10 Modules[module] 11 Classes[class] 12 Overloading[over] 13 Templates[temp] 14 Exception handling[except] 15 Preprocessing directives[cpp]
然而,关于全局名称下划线的规则来自[library],特别是[library]中的[reserved.names]/2 and [global.names]/1,“[intro] through [cpp]”没有涵盖。
[reserved.names]/2 If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
[global.names]/1 Certain sets of names and function signatures are always reserved to the implementation:
- (1.1) Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter ([lex.key]) is reserved to the implementation for any use.
- (1.2) Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
现在,[lex.name]/3 也包含相同的标识符保留规则
In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
- (3.1) Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
- (3.2) Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
违反[lex.name]/3 是格式错误的,不需要诊断(IFNDR),这与未定义的行为不同;根据上面的 [expr.const]/5.7,一些 UB 应该 实际上被诊断出来(constexpr 上下文)。
根据 [intro] 通过 [cpp] [expr.const]/5.7 对 UB 的限制可以说是有意限制规则以避免构造对于典型的 C++ 实现者来说是 UB 而不是 STL 库实施者,例如[库]中的规则。这也可能是一个措辞缺陷,特别是 [lex.name]/3 的规则仅在 [[library] 中 [reserved.names]/2 的“事后”才从 IFNDR 变为 UB。
因此,这种“种类”的未定义行为 (UB) 可以说不属于使表达式无法成为核心常量表达式的 UB。
拥有遵循这些约定的宏、变量或其他成员不是“未定义的行为”。它完全合法,不同于以数字、控制字符或其他类似内容开头的标识符。
以两 (2) 个下划线开头的标识符,例如
typedef uint32_t __my4ByteInt;
不推荐,因为标准库将此约定用于内部标识符,如果您的成员具有相同的名称,它可能会导致问题。
除此之外,这些标识符是合规的。我不确定 MISRA,但即使在那里,我也相当确定命名约定只是建议,不会由编译器检查,而是由第三方分析工具(如 CodeSonar)检查。