CQuiz
Caveat: The quiz is 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 C11 and probably future releases.

If two pointers
p
andq
of the same type point to the same address, thenp == q
must evaluate to true.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.

Consider the following code snippet:
At the end of the code snippet, the value of variable
i
equalsThe rule of thumb is: accessing an object of type
T
through an lvalue of typeU
whereT
andU
are not compatible (modulo few exceptions) invokes undefined behavior. That means, in the example we accessed an object of typeint
through an lvalue of typeshort
which leads to undefined behavior.Have a look at this post for a detailed discussion.

The following two function declarations can be used interchangeably, i.e., they mean exactly the same:
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.

The following function declaration in conjunction with the function definition is legal.
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.

The following function declaration in conjunction with the function definition is legal.
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 adouble
. 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.

Consider the following translation unit consisting of a global variable declaration:
At the point of the declaration of variable
x
the structure typefoo
is unknown. Only later on in the translation unit the type is completed. Is this translation unit legal?This is allowed in certain circumstances as e.g. for global variables. A similar argument holds for arrays with an incomplete type.
This is also mentioned in DR016.

Declaring a variable of type
void
with internal linkage is not legal.Is it legal to declare a variable of type
void
with external linkage?According to the grammar this is legal. Furthermore, it is nowhere stated in the C11 standard that it would not be allowed. However, I cannot think of any real use case and therefore assume that this is only allowed by accident. Note, type
void
is incomplete and cannot be completed. Thus the only allowed operation on variablefoo
is to take its address and assign it to a variable with a completed type.C11 § 6.2.5 Types ¶ 19
The
void
type comprises an empty set of values; it is an incomplete object type that cannot be completed. 
The bit representation of the null pointer must have all bits zero.
The null pointer constant is defined by the C standard. However, the representation of the null pointer at runtime is not. Actually, the representation of pointers in general is not defined by the C standard. For example, the Symbolics Lisp Machine 3600 does not make use of numerical pointers at all but of tuples of the form
<arrayobject, index>
. The representation of the null pointer is then<nil, 0>
. 
Let
NULL
be the null pointer, thenNULL == 0
evaluates to 
The expression
(void *)0
evaluates to the null pointer. 
If the expression
e
evaluates to0
, then it is guaranteed that(void *)e
evaluates to the null pointer.Only the null pointer constant converted to pointer type is guaranteed to equal the null pointer.

If the expression
e
evaluates to the null pointer, then it is guaranteed thate+0
evaluates to the null pointer, too.Null pointer arithmetic is undefined behavior in C.

After the following code snippet the expression
x == y
may evaluate to false.Variable
x
is not initialized and therefore holds an indeterminate value. According to C11 expressions involving indeterminate values result in undefined behavior. Hence “anything” might happen which includes that the expression may evaluate to false. 
Let
T
be a (derived) object type. The first assignment is legal C code. Is the second assignment legal, too?For this question I do not have a short answer. Have a look at this post for a detailed discussion.

The expression
sizeof(int) > 1
evaluates toThe short answer is that operator
sizeof
returns an unsigned integer of typesize_t
. According to the usual arithmetic conversions (C11 § 6.3.1.8) the operand which is signed and has a lower rank than the unsigned operand, is converted to an unsigned integer type of the same rank as the unsigned operand. Any signed integer which is equivalent to1
has all bits set. Such a sequence of bits interpreted as an unsigned integer equals the maximal unsigned integer of each corresponding integer rank. In other words(unsigned int)1
equalsUINT_MAX
. The same holds true for all other integersshort int
,long int
, andlong long int
. Thus, the left operand of the relational operator evaluates to the maximal unsigned integer representable by an unsigned integer whose rank is equivalent to the rank ofsize_t
. Since there exists no unsigned integer with a same rank which is strictly greater, the expression always evaluates tofalse
. 
The following two statements are equivalent.
The first assignment initializes an array with automatic or static storage duration (depends on whether
x
is declared in file or function scope) which is modifiable. Whereas the second assignment initializes a pointer to an array with static storage duration which is not necessarily modifiable. Or in other words arrays are not pointers.Have a look at this post for a detailed discussion.

Let
int a[42];
be an array, then all three expressionsa
and&a
and&a[0]
can be used interchangeably, i.e., they mean exactly the same.All three expressions evaluate to a pointer to the first element of the array. However, each expression has a different type. Have a look at this post for a detailed discussion.

Assume that the variables
a
,b
, andc
are initialized before read.The values for the variables
x
andz
Short answer: The integer promotions require that the value of each variable is promoted to size
int
, then the addition and division is performed. The resulting value is truncated and stored in the corresponding variable of each assignment, respectively. Provided that the addition may overflow the values forx
andz
may not equal.Long answer: The modulo operation is not distributive over division. Lets illustrate the problem by an example. Assume
a=255;
,b=1;
, andc=2;
, then for the first assignment we have that the value stored inx
equals the expression((255 + 1) / 2) % 256
which equals(256 / 2) % 256
which equals128 % 256
which finally equals128
. For the second assignment we have that the value stored iny
equals the expression(255 + 1) % 256
which equals256 % 256
which finally equals0
. N.B. an overflow occurred which is defined behavior for unsigned integers. For the last assignment we then have that the value stored inz
equals the expression(0 / 2) % 256
which equals0 % 256
which finally equals0
. Thereforex == z
is not always the case since128 != 0
.Fun fact 1: The modulo operation is distributive over addition, i.e.,
(a + b) % x == [(a % x) + (b % x)] % x
for alla,b,x
. Thus, if we change the division by an addition, then the values for the variablesx
andz
are always the same.Fun fact 2: We could change the first assignment to
uint8_t x = ((uint8_t)(a + b)) / c;
. Then the values for the variablesx
andz
are always the same, too. 
The expression
sizeof(char) == sizeof('x')
evaluates totrue
for any character constant'x'
.Character constants have type
int
(C11 § 6.4.4.4 paragraph 10). Thus onlysizeof(int) == sizeof('x')
is guaranteed to evaluate totrue
.N.B. in terms of the C11 standard a character constant is either an integer character constant or a wide character constant. The former is a sequence of one or more multibyte characters. Thus 'abc' is a valid integer character constant where the representation is implementationdefined. If an integer character constant contains a single character, then its value equals the integer representation of an object of type
char
which represents the very same single character. 
Consider the following code snippet:
The expression
x+++y

Consider the following code snippet:
The value of variable
y
equalsOperator precedence is well defined. However, the order of evaluation of arithmetic operands is undefined. Thus, the expression
(x=1) + (x=2)
invokes undefined behavior, i.e., it is undefined whether variablex
should equal1
or2
after the assignments. This renders the whole code as undefined.Fun fact: evaluates the expression to
4
and to3
. 
Consider the following code snippet:
The value of variable
y
equalsOperator precedence is well defined and for the logical operators
&&
and
the order of evaluation of operands is well defined, too. With the words of the C standard: between the evaluation of the first and second operand there exists a sequence point. Thus in the example we have that firstx=1
is evaluated which equalstrue
and thenx=2
is evaluated which also equalstrue
which renders the whole expressiontrue
.
Score
You answered 0 out of 0 questions correctly!