考虑以下计划:
#include <cstdio>
int main()
{
int printf=9;
std::printf("%d",printf);
}
使用内置函数名作为变量声明中的标识符是否可以?这个定义良好的程序?我的意思是上面的程序行为定义明确吗?我很想知道C ++标准是否允许使用标准函数名作为变量的标识符
答案 0 :(得分:4)
是的,这是明确定义的行为。您正在创建一个名为printf的int,并且您的范围中当前没有任何名为printf的内容。在标准作用域中有一些名为printf的东西,可能在全局作用域中,但在本地作用域中定义的int printf自动优先。
答案 1 :(得分:4)
它格式正确,因为std::printf
和::printf
(可能也已由<cstdio>
声明!)都声明在与整数相同的范围,因此在块的持续时间内自动优先。
[C++14: 3.3.1/1]:
[..] 为了确定声明的范围,有时可以方便地引用声明的潜在范围。除非潜在范围包含另一个同名声明,否则声明的范围与其潜在范围相同。在这种情况下,内部(包含)声明性区域中声明的潜在范围被排除在外部(包含)声明性区域中的声明范围之外。
例如,you generally wouldn't be able to do this at namespace scope。
它定义明确,因为标准库中的实体名称本身并不是保留名称:
[C++14: 2.11/3]:
此外,一些标识符保留供C ++实现和标准库(17.6.4.3.2)使用,否则不得使用;无需诊断。
[C++14: 17.6.4.3.2/1]:
某些名称和功能签名集始终保留给实现:
- 包含双下划线
_ _
或以下划线后跟大写字母(2.12)开头的每个名称都保留给实现以供任何使用。- 以下划线开头的每个名称都保留给实现,以用作全局命名空间中的名称。
答案 2 :(得分:3)
技术上允许这样做。有一些名称在全局命名空间中保留,但在函数内部,您的变量名称无论如何都不会在函数外部显示,所以不是问题。
使用它是一个糟糕的主意。
请注意这种方法可能存在问题。例如:
#define NULL 0
int main()
{
int NULL = 42;
printf("%d", NULL);
}
是不允许的,因为NULL
是宏,而不是范围标识符。
编辑:我想补充说printf
不是&#34;内置函数&#34;。它是一个&#34; C标准库函数&#34;。 bultin函数类似__builtin_sin
,编译器&#34;知道&#34;这样它就可以得到优化。请注意,内置函数通常使用&#34;保留名称&#34;,以避免始终与现有库和用户定义的名称发生冲突。
答案 3 :(得分:0)
相对于标准库中的标识符,C ++标准仅声明标识符的以下重构
3此外,一些标识符保留供C ++使用 实现和标准库(17.6.4.3.2),不得 否则;无需诊断。
和(17.6.4.3.2全球名称)
1始终保留某些名称和功能签名集 实施:
- 每个包含双下划线_ _的名称或以。开头的名称 下划线后跟一个大写字母(2.12)保留给 实施任何用途。
- 以下划线开头的每个名称都保留给 实现用作全局命名空间中的名称。
因此,您可以使用与标准函数名称一致的标识符。
另一方面,这可能会使读者感到困惑并导致歧义。 考虑到标准允许编译器将标准C函数名称放在全局名称空间中。
答案 4 :(得分:0)
这样做是可以的。因为您定义的变量int printf
不属于std
作为printf
,cstdio
中定义的变量using namespace std;
。所以你的程序名称实际上没有冲突。
但是,如果您声明
std::
在您的计划之前,并且之后在您的计划中没有使用#include<cstdio>
using namespace std;
int main()
{
int printf = 42;
printf("%d", printf);
}
,如果您不小心,它会导致问题。通常,当存在名称冲突时,编译器将使用在最小范围内定义的名称。所以如果你有这样的程序:
error: ‘printf’ cannot be used as a function
编译器将返回
printf
这是因为在此程序中,int
在函数范围内定义为int printf( const char* format, ... )
,在全局范围内定义为函数int main()
。由于函数范围小于全局范围,因此在函数printf
中,int
被解释为int
而不是函数。 var s1 = Symbol.for("foo");
var s2 = Symbol.for("foo");
s1 === s2; // true
不可调用,因此是错误消息。