2013-07-04 16:45:19
找了很多资料,没有说的很明白的,下面是老外的一篇文章,解释的比较清楚,后面给出翻译。
转自:
I constantly see recommendations to #include <cstdio> instead of using stdio.h and the same for the other C headers. What most posters fail to mention is that this should put all the symbols into namespace std and NOT into the global namespace.
This you have to write std::printf(...). Simply writing printf alone will not work .
The same applies to the headers :
cassert ciso646 csetjmp cstdio ctime cctype climits csignal cstdlib cwchar cerrno clocale cstdarg cstring cwctype cfloat cmath cstddef.
This is clearly defined by ISO 14882 in footnote 160:
Most compilers completely fail to implement this correctly and put all the names into both namespaces when using the new headers. As this is incorrect behaviour, it is quite likely to change in the future which means that code you write now may break on newer compilers as they get closer to the standard.
As an aside note that many compilers fail to give even a warning (and even on the highest warning level) when you write void main(), even though the standard clearly dictates that main MUST return int.
Nathan Myers, a member of the C++ standards committee wrote this paper on header strategy here:
Markus
大致翻译了一下,如下:
经常看到有建议说要使用 #include <cstdio>代替 #include stdio.h,但很少有人提及这将把所有的symbol放进std namespace,而非 global namespace.这样,就必须写成std::printf(...)(注意是必须,但有的编译器却能通过,具体解释见下面),简单的写成printf是不行的。
这对于以下的有文件同样:cassert ciso646 csetjmp cstdio ctime cctype climits csignal cstdlib cwchar cerrno clocale cstdarg cstring cwctype cfloat cmath cstddef.
这在ISO 14882 in footnote 160:中有明确说明:
也就是:".h"头文件将所有名字放在global namespace中,在新的方式下(指的是诸如cstdio这样的头文件),名字是放在namespace std中的。因此,新的方式是所有应用推荐的方式,除非是要编写与C严格兼容的程序。
许多编译器不能完全正确地实施这个规则,在使用新的header时,将所有的名字放入两个namespace。但因为这是不正确的,所以在以后很可能会改变(编译器会有所优化),这意味着你现在写的代码在新的编译器上可能会出错,因为它们更接近于新的标准。
许多编译器连一个warning都不能给出(即使是在最高warning级别下),比如当你写一个void main()时,许多编译器都不会给出warning,即使标准明确指出main函数必须返回int型数据。
C++标准委员会的成员Nathan Myers写了一篇关于header strategy文章:
小结:
- 在C++下,若要使用C中已有库中的函数如stdio,文件包含方式为前面加一个c,同时去掉.h后缀,如#include <cstdio>,同时必须加上using namaspace;对于其他类似的函数同样;
- 对于C++特有的库,直接用去掉.h后缀的文件包含,并加上using namaspace;
VS2010下实例分析:
针对上面的讨论,在VS2010下,用一段小代码测试
在C++中,若要使用printf,我们知道该函数在C中是在stdio中包含的
文件包含写法1(标准C++风格,推荐):
对于C++,标准的写法如下
1 #include2 using namespace std; 3 4 int main() 5 { 6 int a = 16; 7 8 printf("%d\n",a); 9 10 return 0;11 }
编译,没有waring,没有error,运行可正确输出。
文件包含写法2(旧式C风格,不推荐,且在VS2010下编译出错):
C标准的写法,如下:
1 #include
但是在VS2010下编译,会报错找不到该头文件:Cannot open include file: 'cstdio.h': No such file or directory
疑问:根据上面的解释,虽然写的是C++的代码,但是这样写也可以,是标准支持的,只不过标准推荐用第一种写法。此处为何编译出错,原因未知???
文件包含写法3(错误的写法,但是大多数编译器不活给出waring或error,仍可编译通过,在以后的编译器下可能会出错,强烈不推荐):
但如果文件包含去掉using namespace std;,即写成:
1 #include
编译,运行结果与文件包含写法1完全一样,没有任何warning。这就是上面所说的许多编译器不能完全正确地实施这个规则,在使用新的header时,将所有的名字放入两个namespace。在以后的编译器下可能会出错
疑问:使用printf函数,包含iostream也可以???
我们知道printf对于C而言,是包含在stdio中的,对于C++则是在cstdio中的,但是奇怪的是,我在VS2010下,只包含iostream,如下:
1 #include
居然也可正确编译、运行,原因未知,可能还是类似于文件包含写法3的原因,编译器没有很好的处理C与C++的文件包含问题。
在iostream中并没有包含printf函数,为何可正确使用printf???
同样地,写成
1 #include2 using namespace std;
但是,若要使用cout、cin等iostraem中真正包含的函数,就必须加上using namespace std;的声明,而不能只写#include <iostream>,如下:
1 #include2 //using namespace std; 3 4 int main() 5 { 6 int a = 16; 7 8 //printf("%d\n",a); 9 cout< <
会提示没有声明cout、endl:error C2065: 'cout' : undeclared identifier
C++头文件包含何时要加.h,何时不加.h,何时在前面加c?
C++中不要#include <iostream.h>,不要#include <string.h>,因为它们已经被C++标准明确的废弃了,请改为 #include <iostream> 和 #include <cstring>.规则就是:
a. 如果这个头文件是旧C++特有的,那么去掉 h后缀,并放入std名字空间,
比如 iostream.h 变为 iostream.
因此,若要使用iostream库中函数,文件包含为
#include <iostream>
using namespace std;若只写#include <iostream>,而没有using namespace std;,会报错:error C2065: 'cout' : undeclared identifier,因为cout是在std中命名的,必须加上using namespace std;
可能在早期的编译器中,也支持#include <iostream.h>,可不用写using namespace std,但用VS2010编译,会报错Cannot open include file: 'iostream.h': No such file or directory。
b. 如果这个头文件是C也有的,那么去掉 h后缀,增加一个c前缀,比如 string.h
变为 cstring;stdio.h 变为 cstdio, 等等
Cplusplus的网站:
Input and Output operations can also be performed in C++ using the C Standard Input and Output Library (cstdio, known as stdio.h in the C language). This library uses what are called streams to operate with physical devices such as keyboards, printers, terminals or with any other type of files supported by the system. Streams are an abstraction to interact with these in an uniform way; All streams have similar properties independently of the individual characteristics of the physical media they are associated with.
下面来自百度百科:
下面参考:
在C语言中,stdio.h 头文件是主要的。而在后来的C++语言中,C只是C++的一个子集,且C++中,已不推荐再用C的类库,但为了对已有代码的保护,还是对原来的头文件支持。
cstdio是c++从C的stdio.h继承来的,在前面加C同时不要H后缀,在C++环境当然是选用前者,两者内容都一样,只是cstdio头文件中定义的名字被定义在命名空间std中。使用后者就会带来额外的负担,需要区分哪些是标准库明是C++特有的,哪些是继承过来的!!所以在C++中要尽量避免C风格的出现!!cstdio code:// cstdio standard header#pragma once#ifndef _CSTDIO_#define _CSTDIO_#include <yvals.h>#ifdef _STD_USING#undef _STD_USING #include <stdio.h>#define _STD_USING#else #include <stdio.h>#endif #define _HAS_CONVENTIONAL_CLIB 1#define _IOBASE _base#define _IOPTR _ptr#define _IOCNT _cnt#ifndef RC_INVOKED#if _GLOBAL_USING_STD_BEGINusing ::size_t; using ::fpos_t; using ::FILE;using ::clearerr; using ::fclose; using ::feof;using ::ferror; using ::fflush; using ::fgetc;using ::fgetpos; using ::fgets; using ::fopen;using ::fprintf; using ::fputc; using ::fputs;using ::fread; using ::freopen; using ::fscanf;using ::fseek; using ::fsetpos; using ::ftell;using ::fwrite; using ::getc; using ::getchar;using ::gets; using ::perror;using ::putc; using ::putchar;using ::printf; using ::puts; using ::remove;using ::rename; using ::rewind; using ::scanf;using ::setbuf; using ::setvbuf; using ::sprintf;using ::sscanf; using ::tmpfile; using ::tmpnam;using ::ungetc; using ::vfprintf; using ::vprintf;using ::vsprintf;_STD_END#endif #endif #ifndef _Filet#define _Filet FILE#endif #ifndef _FPOSOFF #define _FPOSOFF(fp) ((long)(fp))#endif #endif