停止由 C++ 引起的 <stdio.h> 定义的误捕包括
Stop bycatch of <stdio.h> definitions caused by C++ includes
在对 , I was shown a code example 的评论中似乎使用了 printf
和 puts
而没有包含 <stdio.h>
但在线编译器没有抱怨。[ 1] 为了了解发生了什么,我将它复制到本地 IDE。
还原成相关的include和output,基本上就是这样:
#include <string>
#include <map>
#include <optional>
int main() {
printf("Answer %d\n", 42);
puts("Question?");
}
使用 gcc 8.1.0(与 Clode::Blocks 20.03 一起打包)进行实验,我发现包含可以进一步减少到
<string>
或 <map>
或 C++17 中的 <optional>
(ISO/GCC)
<string>
或 C++11/C++14 中的 <map>
(ISO/GCC)
<string>
在 C++98 中 (ISO/GCC)
还有一个示例测试 - C++14 (gcc 8.3) - on ideone.com 编译并运行良好:
#include <iostream>
int main() {
printf("printf without #include <stdio.h>\n");
return 0;
}
<stdio.h>
中的其他定义也是如此,例如 FILE
。
我在 cppreference.com
找不到任何信息
- std::printf, std::fprintf, std::sprintf, std::snprintf - cppreference.com
- std::puts - cppreference.com
- printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s - cppreference.com
- puts - cppreference.com
我也尝试了几个网络和 SO 搜索,但到目前为止没有成功。
虽然可能对于小示例免费获得一些强大的功能很方便,但一个严肃的项目可能会受到影响:除了相对容易修复编译器错误之外,我明白了严重运行时错误的危险。
怎样才能有效control/prevent这种包容?
[1] 引用的代码现在包含 include 语句,但我很确定它在我复制它的阶段没有..或者我只是复制了一部分? ...无论如何,观察到的行为如上所述。
恐怕你不能。
标准要求众所周知的包含文件声明相关名称,但不阻止它们包含其他 files/names,如果库实现发现它有用的话。
换句话说,在包含 iostream
之后,您确定属于它的所有名称都已正确声明,但您无法知道(除非检查文件本身)是否定义了其他名称,或者是否其他标准文件已包含在内。在这里,您的实现选择自动包含 stdio.h
,但不同的(标准库)实现可以选择不包含它。您已进入未指定...
的世界
除了关于“纯度”的任何争论之外,我看不出包含这些函数的声明有何危害。事实上, 没有 并让编译器隐含地假设 int printf()
——尽管只有 C 编译器会这样做,C++ 不会——这是在自找麻烦。
printf
是 C 语言标准的一部分。尽管 C++ 不是 C,但它们的生态系统之间有太多重叠,以至于 C++ 也将 printf
视为实现运行时环境的一部分,就像它与 C 标准库中的所有其他函数一样。
因此,所有这些符号都是保留的。除了实际实现运行时库本身之外,您没有必要自己定义这些名称的符号。
#include
预处理器指令只是内联文本替换,其中文本是从其他文件中提取的。
(extern
) symbol declarations 不会创建这些名称的符号,但它们会确保您不会 自己重新定义这些符号。
所以我真的不明白你对运行时错误的担忧从何而来。
在对 printf
和 puts
而没有包含 <stdio.h>
但在线编译器没有抱怨。[ 1] 为了了解发生了什么,我将它复制到本地 IDE。
还原成相关的include和output,基本上就是这样:
#include <string>
#include <map>
#include <optional>
int main() {
printf("Answer %d\n", 42);
puts("Question?");
}
使用 gcc 8.1.0(与 Clode::Blocks 20.03 一起打包)进行实验,我发现包含可以进一步减少到
<string>
或<map>
或 C++17 中的<optional>
(ISO/GCC)<string>
或 C++11/C++14 中的<map>
(ISO/GCC)<string>
在 C++98 中 (ISO/GCC)
还有一个示例测试 - C++14 (gcc 8.3) - on ideone.com 编译并运行良好:
#include <iostream>
int main() {
printf("printf without #include <stdio.h>\n");
return 0;
}
<stdio.h>
中的其他定义也是如此,例如 FILE
。
我在 cppreference.com
找不到任何信息- std::printf, std::fprintf, std::sprintf, std::snprintf - cppreference.com
- std::puts - cppreference.com
- printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s - cppreference.com
- puts - cppreference.com
我也尝试了几个网络和 SO 搜索,但到目前为止没有成功。
虽然可能对于小示例免费获得一些强大的功能很方便,但一个严肃的项目可能会受到影响:除了相对容易修复编译器错误之外,我明白了严重运行时错误的危险。
怎样才能有效control/prevent这种包容?
[1] 引用的代码现在包含 include 语句,但我很确定它在我复制它的阶段没有..或者我只是复制了一部分? ...无论如何,观察到的行为如上所述。
恐怕你不能。
标准要求众所周知的包含文件声明相关名称,但不阻止它们包含其他 files/names,如果库实现发现它有用的话。
换句话说,在包含 iostream
之后,您确定属于它的所有名称都已正确声明,但您无法知道(除非检查文件本身)是否定义了其他名称,或者是否其他标准文件已包含在内。在这里,您的实现选择自动包含 stdio.h
,但不同的(标准库)实现可以选择不包含它。您已进入未指定...
除了关于“纯度”的任何争论之外,我看不出包含这些函数的声明有何危害。事实上, 没有 并让编译器隐含地假设 int printf()
——尽管只有 C 编译器会这样做,C++ 不会——这是在自找麻烦。
printf
是 C 语言标准的一部分。尽管 C++ 不是 C,但它们的生态系统之间有太多重叠,以至于 C++ 也将 printf
视为实现运行时环境的一部分,就像它与 C 标准库中的所有其他函数一样。
因此,所有这些符号都是保留的。除了实际实现运行时库本身之外,您没有必要自己定义这些名称的符号。
#include
预处理器指令只是内联文本替换,其中文本是从其他文件中提取的。
(extern
) symbol declarations 不会创建这些名称的符号,但它们会确保您不会 自己重新定义这些符号。
所以我真的不明白你对运行时错误的担忧从何而来。