对于C语言,不同的编译器采用了不同的实现,并且在不同平台上表现也不同。脱离具体环境探讨C的细节行为是没有意义的,以下是我所使用的环境,大部分内容都经过测试,且所有测试结果基于这个环境获得,为简化起见,省略了异常处理。我不希望读者死记硬背这些细节,而是能在自己的平台上进行实验从而获得对应的结果。另外,本文仅仅关注于C,可能会考虑C++的表现,但在C++和C#环境下的编译器所获得的看似C代码而实不同的结果不作为参考。基础的东西比如“函数参数传值”、“转义字符”、“else的最近配对”、“case的下落(fall through)”、“符号常量NULL代表常量0”、“restrict关键字”、“使用%p输出指针”、“const的指针常量和常量指针”等本文不会重复。
了解这些细节并在自己的平台上进行实验并不是鼓励你去写模棱两可、过于依赖平台和实现的代码(除非有非这么做不可的必要),而是对这种代码有鉴别能力和理解能力,尽量避免和修正。
另外,在其他平台上的不同行为欢迎列出,但不会对原文中实现相关、机器相关的细节的具体表现进行补充说明。
如有错误,恳请指正。由于目前时间有限,可能不能及时回复,请谅解。
编译器:gcc 4.4.3,默认无任何编译选项。
编译环境:Ubuntu10.04LTS,32×86
标准:默认为ISO C99的GNU方言,不使用任何-std=选项
以下是该环境中man gcc的部分结果:
-std=Determine the language standard. This option is currently only supported when compiling C or C++.
The compiler can accept several base standards, such as c89 or c++98, and GNU dialects of those standards,such as gnu89 or gnu++98. By specifying a base standard, the compiler will accept all programs followingthat standard and those using GNU extensions that do not contradict it. For example, -std=c89 turns offcertain features of GCC that are incompatible with ISO C90, such as the “asm” and “typeof” keywords, butnot other GNU extensions that do not have a meaning in ISO C90, such as omitting the middle term of a “?:”expression. On the other hand, by specifying a GNU dialect of a standard, all features the compilersupport are enabled, even when those features change the meaning of the base standard and some strict-conforming programs may be rejected. The particular standard is used by -pedantic to identify whichfeatures are GNU extensions given that version of the standard. For example -std=gnu89 -pedantic wouldwarn about C++ style // comments, while -std=gnu99 -pedantic would not.
A value for this option must be provided; possible values are
…
gnu89GNU dialect of ISO C90 (including some C99 features). This is the default for C code.
gnu99gnu9xGNU dialect of ISO C99. When ISO C99 is fully implemented in GCC, this will become the default. Thename gnu9x is deprecated.
…
gcc4.4.3是2010年发布的,编译器所采用标准的判断来自于最后一行。
另外,为了进行对照,个别实例会使用Clang进行补充。
主要参考资料:
为了不因不同标准而导致混淆,对于参考资料的引用都将注明出处的简称。
1.The C Programming Language 2nd edition,《C程序设计语言(英文版·第2版)》,Brian W. Kernighan & Dennis M. Ritchie 著,以下简称K&R
2.C: A Reference Manual 5thedition,《C语言参考手册(原书第五版)》,Samuel Harbison III & Guy L. Steele Jr.著,徐波译,机械工业出版社,以下简称CARM
优秀的案头参考手册。涵盖了传统C、C89、C89修正案1和C99(此书译者序)。 遗憾的是中文版没有英文版的术语索引(Index)。
3.ISO/IEC 9899:1999,以下简称C99或C99标准
由于使用的编译器和环境而作为权威的参考。
一、编程细节:
细节1:printf的参数必须使用\n换行(newline)而不是在参数里使用回车。
来源:K&R 1.1,P7
printf(
结果:
编译器Error。
细节2:printf使用了格式化控制符%d但没有对应参数
来源:某公司面试题
printf();
结果:
编译器warning: too few arguments for format
运行时显示一个随机值。
对照:
使用clang,提示1 diagnostic generated.
运行时总是显示0。
分析:
K&R提到,如果参数不够,会FAIL。C99则把这认定为未定义行为(可参见C99标准中的fprintf部分,,它的行为与printf类似)。
相关:
%s对于” “和””的处理演示。我不确定是否实现相关或者未定义行为。
printf(,” “,””);
输出:
||
细节3: getchar()返回值是int,而非char;兼谈char型是否有符号及EOF的值
分析:
(c =getchar())!=EOF常用于判断输入是否结束,而char的范围不一定能容纳EOF,因此用int接收返回值。
你说只有有缘人才可以取下,我看着你手中的戒指,