考虑以下程序:
#include <cstdio>
int main()
{
int printf=9;
std::printf("%d",printf);
}
在变量声明中使用内置函数名作为标识符是否可以?这是定义明确的程序吗?我的意思是上述程序的行为是否定义明确?我很想知道 C++ 标准是否允许使用标准函数名作为变量的标识符
考虑以下程序:
#include <cstdio>
int main()
{
int printf=9;
std::printf("%d",printf);
}
在变量声明中使用内置函数名作为标识符是否可以?这是定义明确的程序吗?我的意思是上述程序的行为是否定义明确?我很想知道 C++ 标准是否允许使用标准函数名作为变量的标识符
它的格式是正确的,因为std::printf
nor ::printf
(也可能已由<cstdio>
! 声明)在与您的整数相同的范围内声明,因此在块的持续时间内自动优先。
[C++14: 3.3.1/1]:
[..]要确定声明的范围,有时参考声明的潜在范围很方便。除非潜在范围包含另一个同名声明,否则声明的范围与其潜在范围相同。在这种情况下,内部(包含)声明性区域中的声明的潜在范围被排除在外部(包含)声明性区域中的声明范围之外。
它的定义很好,因为标准库中的实体名称不是固有的保留名称:
[C++14: 2.11/3]:
此外,某些标识符保留供 C++ 实现和标准库 (17.6.4.3.2) 使用,不得以其他方式使用;不需要诊断。
[C++14: 17.6.4.3.2/1]:
某些名称和函数签名集始终保留给实现:
- 每个包含双下划线
_ _
或以下划线后跟大写字母 (2.12) 的名称都保留给实现以供任何使用。- 每个以下划线开头的名称都保留给实现用作全局名称空间中的名称。
是的,这是定义明确的行为。您正在创建一个名为 printf 的 int,并且您的范围内当前没有任何名为 printf 的内容。在标准范围内有一个名为 printf 的东西,可能在全局范围内,但在本地范围内定义的 int printf 自动优先。
技术上允许这样做。在全局命名空间中保留了一些名称,但在函数内部,您的变量名无论如何都不会在函数外部可见,因此不是问题。
使用它是一个糟糕的主意。
请注意,这种方法可能存在问题。例如:
#define NULL 0
int main()
{
int NULL = 42;
printf("%d", NULL);
}
不允许,因为NULL
它是一个宏,而不是一个范围标识符。
编辑:我要补充一点,这printf
不是“内置功能”。它是一个“C 标准库函数”。bultin 函数类似于__builtin_sin
,编译器“知道”以便对其进行优化。请注意,内置函数通常使用“保留名称”,以避免始终与现有库和用户定义的名称发生冲突。
这样做是可以的。因为你定义的变量int printf
不属于命名空间std
as 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
不可调用,因此出现错误消息。
相对于标准库中的标识符,C++ 标准仅规定了标识符的以下重构
3 此外,一些标识符保留供 C++ 实现和标准库 (17.6.4.3.2)使用,不得以其他方式使用;不需要诊断。
和(17.6.4.3.2 全局名称)
1 某些名称和函数签名集始终保留给实现:
— 每个包含双下划线 _ _ 或以下划线后跟大写字母 (2.12) 的名称都保留给实现以供任何使用。
— 每个以下划线开头的名称都保留给实现用作全局名称空间中的名称。
因此,您可以使用与标准函数名称一致的标识符。
另一方面,这会使代码的读者感到困惑并导致歧义。考虑到标准允许编译器将标准 C 函数名称放在全局命名空间中。