stdio.h及cstdio的区别

2013-07-04 16:45:19

找了很多资料,没有说的很明白的,下面是老外的一篇文章,解释的比较清楚,后面给出翻译。

Clarifying stdio.h versus cstdio

转自:http://forums.codeguru.com/showthread.php?344430-Clarifying-stdio-h-versus-cstdio

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:

 
The ".h" headers dump all their names into the global namespace, whereas the newer forms keep their names in namespace
std. Therefore, the newer forms are the preferred forms for all uses except for C++ programs which are intended to be strictly compatible
with C.

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:http://www.cantrip.org/cheaders.html

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:中有明确说明:

 

 
The ".h" headers dump all their names into the global namespace, whereas the newer forms keep their names in namespace
std. Therefore, the newer forms are the preferred forms for all uses except for C++ programs which are intended to be strictly compatible
with C.

 

也就是:".h"头文件将所有名字放在global namespace中,在新的方式下(指的是诸如cstdio这样的头文件),名字是放在namespace std中的。因此,新的方式是所有应用推荐的方式,除非是要编写与C严格兼容的程序。

 

 

许多编译器不能完全正确地实施这个规则,在使用新的header时,将所有的名字放入两个namespace。但因为这是不正确的,所以在以后很可能会改变(编译器会有所优化),这意味着你现在写的代码在新的编译器上可能会出错,因为它们更接近于新的标准。

许多编译器连一个warning都不能给出(即使是在最高warning级别下),比如当你写一个void main()时,许多编译器都不会给出warning,即使标准明确指出main函数必须返回int型数据。

C++标准委员会的成员Nathan Myers写了一篇关于header strategy文章:http://www.cantrip.org/cheaders.html

小结:

  1. 在C++下,若要使用C中已有库中的函数如stdio,文件包含方式为前面加一个c,同时去掉.h后缀,如#include <cstdio>,同时必须加上using namaspace;对于其他类似的函数同样;
  2. 对于C++特有的库,直接用去掉.h后缀的文件包含,并加上using namaspace;

VS2010下实例分析:

针对上面的讨论,在VS2010下,用一段小代码测试

在C++中,若要使用printf,我们知道该函数在C中是在stdio中包含的

文件包含写法1(标准C++风格,推荐):

对于C++,标准的写法如下

 

 1 #include <cstdio>
 2 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 <stdio.h>

 

但是在VS2010下编译,会报错找不到该头文件:Cannot open include file: 'cstdio.h': No such file or directory

疑问:根据上面的解释,虽然写的是C++的代码,但是这样写也可以,是标准支持的,只不过标准推荐用第一种写法。此处为何编译出错,原因未知???

文件包含写法3(错误的写法,但是大多数编译器不活给出waring或error,仍可编译通过,在以后的编译器下可能会出错,强烈不推荐):

但如果文件包含去掉using namespace std;,即写成:

1 #include <cstdio>

编译,运行结果与文件包含写法1完全一样,没有任何warning。这就是上面所说的许多编译器不能完全正确地实施这个规则,在使用新的header时,将所有的名字放入两个namespace。在以后的编译器下可能会出错

疑问:使用printf函数,包含iostream也可以???

我们知道printf对于C而言,是包含在stdio中的,对于C++则是在cstdio中的,但是奇怪的是,我在VS2010下,只包含iostream,如下:

 

1 #include <iostream>

 

 

 

居然也可正确编译、运行,原因未知,可能还是类似于文件包含写法3的原因,编译器没有很好的处理C与C++的文件包含问题。

在iostream中并没有包含printf函数,为何可正确使用printf???

同样地,写成

1 #include <iostream>
2 using namespace std;

但是,若要使用cout、cin等iostraem中真正包含的函数,就必须加上using namespace std;的声明,而不能只写#include <iostream>,如下:

 1 #include <iostream>
 2 //using namespace std;
 3 
 4 int main()
 5 {
 6     int a = 16;
 7 
 8     //printf("%d\n",a);
 9     cout<<a<<endl;
10     return 0;
11 }

会提示没有声明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的网站:http://www.cplusplus.com/reference/cstdio/

 

C library to perform Input/Output operations

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.

 


下面来自百度百科:

cstdio是将stdio.h的内容用C++头文件的形式表示出来。stdio.h是C标准函数库中的头文件,即:standard buffered input&output。提供基本的文字的输入输出流操作(包括屏幕和文件等)。由于C语言并没有提供专用于文字输入输出的关键字,所以该库是最普遍的C语言程序加载库。
stdio.h是以往的C和C++的头文件,cstdio是标准C++(STL),且cstdio中的函数都是定义在一个名字空间std里面的,如果要调用这个名字空间的函数,必须得加std::或者在文件中声明use namespace std。
<cstdio>
Visual Studio 2012 - Visual C++
<cstdio>
定义在标准C库头stdio.h传统上定义的宏。
#if<TRADITIONAL C HEADERS>
#include <stdio.h>
#undef clearerr
#undef feof
#undef ferror
#undef getc
#undef getchar
#undef putc
#undef putchar
namespace std {
using ::fclose;
using ::feof;
using ::ferror;
using ::fflush;
using ::fgetc;
using ::fgetpos;
using ::fgets;
using ::FILE;
using ::clearerr;
using ::fopen;
using ::fprintf;
using ::fpos_t;
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 ::size_t;
using ::sprintf;
using ::sscanf;
using::tmpfile;
using ::tmpnam;
using ::ungetc;
using ::vfprintf;
using ::vprintf;
using ::vsprintf;
}
#endif

 

下面参考:http://no001.blog.51cto.com/1142339/1065812

在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_BEGIN
using ::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 

 

 

posted @ 2013-07-04 20:06  永不止步,永无止境  阅读(20600)  评论(1编辑  收藏  举报