D P. D P. - 1 month ago 12
C Question

C language If statement

I am new to C language and trying to figure out the meaning of the following code.

In here

if (!msize)
checking to see if
msize
is zero or if
msize
is NULL ?

if (!msize)
msize = 1 / msize; /* provoke a signal */

//Example 1: A division-by-zero misuse, in lib/mpi/mpi-pow.c of the Linux kernel, where the entire code will be optimized away.
//Compilers, GCC 4.7 and Clang 3.1

Answer

It depends on the type of msize.

  • If msize is a pointer, it tests whether it is NULL.

  • If msize is not a pointer, it tests whether it is 0.

This distinction may seem pedantic, but it's important. While NULL is actually 0 on most systems, the C standard allows it to be any other value.


I did some further reading, because I started to doubt whether my understanding above is correct.

Here are relevant parts of the C standard.

§6.5.3.3 Unary arithmetic operators

(5) The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

§6.3.2.3 Pointers

(3) An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

(6) Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

Footnotes: 66 The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.

As you can see, 0 is kind of a magic number in C. For systems with a non-zero NULL, I expect that the actual behaviour of !msize may be implementation-defined. In any case, this is all a bit nit-picky.

I tracked down the source of your example in the paper: Undefined Behavior: What Happened to My Code?. The text discussing your example states:

As mentioned earlier, at the instruction set level, x86 raises an exception for a division by zero [17, 3.2], while MIPS [22, A.6] and PowerPC [15, 3.3.38] silently ignore it. A division by zero in C is undefined behavior [19, 6.5.5], and a compiler can thus simply assume that the divisor is always non-zero.

Figure 1 shows a division-by-zero misuse in the Linux kernel. From the programmer’s comment it is clear that the intention is to signal an error in case msize is zero. When compiling with GCC, this code behaves as intended on an x86, but not on a PowerPC, because it will not generate an exception. When compiling with Clang, the result is even more surprising. Clang assumes that the divisor msize must be non-zero—on any system—since otherwise the division is undefined. Combined with this assumption, the zero check !msize becomes always false, since msize cannot be both zero and non-zero. The compiler determines that the whole block of code is unreachable and removes it, which has the unexpected effect of removing the programmer’s original intention of guarding against the case when msize is zero.

So in your case, the answer you really needed was yes: it tests whether msize is 0.