C Programming Language Quiz
C Programming Language Quiz
C Programming Language Quiz This quiz is about quirks of the programming language C and intended for fun and educational purpose. The one or the other question is more academic, i.e., it should make you think ;-) Unless otherwise stated, the questions and corresponding answers are independent of a specific version of the C standard. Thus the answers are the same considering C89 up to and including C17 and probably future releases.
C 语言编程测验。本测验旨在探讨 C 语言中的一些怪癖,兼具趣味性与教育意义。其中一些问题偏向学术性,即旨在引发你的思考 ;-) 除非另有说明,否则问题及其对应的答案与特定的 C 标准版本无关。因此,从 C89 到 C17 以及未来的版本,这些答案均适用。
If two pointers p and q of the same type point to the same address, then p == q must evaluate to true. Yes No Short answer: Comparing two pointers which are derived from two different objects which are not part of the same aggregate or union object invokes undefined behavior. Have a look at this post for a detailed discussion.
如果两个相同类型的指针 p 和 q 指向同一个地址,那么 p == q 的结果一定为真。是 否。简短回答:比较两个源自不同对象(且这些对象不属于同一个聚合体或联合体)的指针会触发未定义行为。详细讨论请参阅此文章。
Consider the following code snippet where an object of type int is accessed through lvalues of type short and unsigned char: int i = 42; short *s = (short *) &i; unsigned char *c = (unsigned char *) &i; *s; // (A) *c; // (B) (A) and (B) invoke undefined behavior (A) invokes undefined behavior but (B) is legal (B) invokes undefined behavior but (A) is legal (A) and (B) are legal
考虑以下代码片段,其中一个 int 类型的对象通过 short 和 unsigned char 类型的左值进行访问:int i = 42; short *s = (short *) &i; unsigned char *c = (unsigned char *) &i; *s; // (A) *c; // (B) (A) 和 (B) 均触发未定义行为 (A) 触发未定义行为但 (B) 合法 (B) 触发未定义行为但 (A) 合法 (A) 和 (B) 均合法
The rule of thumb is: accessing an object of type T through an lvalue of type U where T and U are not compatible (modulo few exceptions) invokes undefined behavior—according to the strict aliasing rules. That means, in the example we accessed an object of type int through an lvalue of type short which leads to undefined behavior. One exception to the rule is that a character pointer may alias any other pointer, i.e., any object may be accessed through a character pointer. Note, only type unsigned char is guaranteed to have no padding bits and therefore has no trap representation which could invoke undefined behavior (since C11 also signed char is guaranteed to have no padding bits). Thus (A) invokes undefined behavior whereas (B) is legal. Have a look at this post for a detailed discussion.
经验法则是:根据严格别名规则(strict aliasing rules),通过类型 U 的左值访问类型 T 的对象(且 T 与 U 不兼容,少数例外除外)会触发未定义行为。这意味着在上述示例中,我们通过 short 类型的左值访问了 int 类型的对象,从而导致了未定义行为。该规则的一个例外是字符指针可以别名任何其他指针,即任何对象都可以通过字符指针进行访问。注意,只有 unsigned char 类型保证没有填充位,因此没有可能触发未定义行为的陷阱表示(自 C11 起,signed char 也保证没有填充位)。因此,(A) 触发未定义行为,而 (B) 是合法的。详细讨论请参阅此文章。
It may make a difference whether an integer constant is given in decimal or hexadecimal format. In other words the meaning may be different. Yes No
整数常量以十进制还是十六进制格式给出可能会产生差异。换句话说,其含义可能不同。是 否。
In a nutshell the type of an unsuffixed decimal constant is always signed whereas of a hexadecimal constant the type may be signed or unsigned. C17 § 6.4.4.1 Integer constants ¶ 5 The type of an integer constant is the first of the corresponding list in which its value can be represented.
简而言之,无后缀十进制常量的类型始终是有符号的,而十六进制常量的类型则可能是带符号或无符号的。C17 § 6.4.4.1 整数常量 ¶ 5:整数常量的类型是对应列表中第一个能够表示其值的类型。
Thus for constants between INT_MAX+1 and UINT_MAX the type differs depending on whether the constant is given in decimal or hexadecimal format. In certain cases this might lead to unexpected effects. One example are functions with a variable number of arguments. void foo(int n, …); void bar(void) { foo(42, 0x80000000); foo(42, 2147483648); } Depending on the ABI and width of integer types of a platform, the function calls may differ.
因此,对于介于 INT_MAX+1 和 UINT_MAX 之间的常量,其类型取决于该常量是以十进制还是十六进制格式给出的。在某些情况下,这可能导致意外的影响。一个例子是具有可变参数的函数。void foo(int n, …); void bar(void) { foo(42, 0x80000000); foo(42, 2147483648); } 根据平台的 ABI 和整数类型的宽度,函数调用可能会有所不同。
Of course, there are plenty examples about arithmetic expressions which suffer from this nuance as e.g. uint64_t x = 0x80000000 << 1; uint64_t y = 2147483648 << 1; where x equals zero and y equals 2^32 assuming that int is 32-bit wide. We may not only run into different behavior on the same platform but also across which results in portability problems. Arithmetic expressions may lead to different results on different platforms. For example, expression -1 < 0x8000 evaluates to true on a platform where int is 32-bit wide and to false where int is 16-bit wide.
当然,有许多算术表达式会受到这一细微差别的影响,例如 uint64_t x = 0x80000000 << 1; uint64_t y = 2147483648 << 1; 在假设 int 为 32 位宽的情况下,x 等于 0,而 y 等于 2^32。我们不仅可能在同一平台上遇到不同的行为,还可能在不同平台间遇到差异,从而导致可移植性问题。算术表达式在不同平台上可能产生不同的结果。例如,表达式 -1 < 0x8000 在 int 为 32 位宽的平台上结果为真,而在 int 为 16 位宽的平台上结果为假。
The following two function declarations can be used interchangeably, i.e., they mean exactly the same: int foo(); int foo(void); Yes No The short answer is that the former declares a function with an unknown number and types of arguments while the latter declares a function without any argument, i.e., it is a nullary function. Have a look at this post for a detailed discussion.
以下两个函数声明可以互换使用,即它们的含义完全相同:int foo(); int foo(void); 是 否。简短回答是:前者声明了一个参数数量和类型未知的函数,而后者声明了一个没有任何参数的函数,即零元函数。详细讨论请参阅此文章。
The following function declaration in conjunction with the function definition is legal. void foo(); void foo(int a) { } Yes No That is a valid function declaration and definition. The declaration only introduces the function name foo without defining the number and types of arguments. Have a look at this post for a detailed discussion.
以下函数声明与函数定义结合使用是合法的。void foo(); void foo(int a) { } 是 否。这是一个有效的函数声明和定义。该声明仅引入了函数名 foo,而没有定义参数的数量和类型。详细讨论请参阅此文章。
The following function declaration in conjunction with the function definition is legal. void foo(); void foo(float a) { } Yes No This is not a valid function declaration in conjunction with the definition. The short answer is that whenever a function is called where no prototype is available, then the default argument promotions are applied. For example, a float is promoted to a double. In this case, the function type is not compatible with the function type after the default argument promotions. Have a look at this post for a detailed discussion.
以下函数声明与函数定义结合使用是合法的。void foo(); void foo(float a) { } 是 否。这与定义结合使用时不是有效的函数声明。简短回答是:每当调用没有可用原型的函数时,都会应用默认参数提升。例如,float 会被提升为 double。在这种情况下,函数类型与默认参数提升后的函数类型不兼容。详细讨论请参阅此文章。