Hacker News new | ask | show | jobs
by Moral_ 4125 days ago
The first two invoke UB and are thus completely illogical.
5 comments

The first invokes UB if you assume that x is a local variable, and the second doesn't at all as far as I can tell. Care to explain?

To elaborate, the second expression has an underflow at 1 - sizeof(int) on an unsigned integer (promotion due to sizeof being unsigned), which is perfectly well defined:

"if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type."

The right shift is fine on a signed or unsigned integer. For the unsigned case (which is this one due to operator precedence), the behavior is well defined. For signed, implementation defined.

EDIT: The right shift is in fact UB assuming sizeof(int) <= 4.

The behavior is only well defined if the shift amount is strictly less than the width of the operand. If `size_t` is 32 bits, then shifting right by 32 bits is undefined.

I know of three different ways in which platforms implement shifts by greater than the word size.

Yep, you're right. I knew left shift for signed/unsigned as it is more complicated and I've had to look it up more often, but I forgot that right shift can be UB for unsigned integral types as well.
The example is written in a strange way. You're supposed to assume x is initialized ("for most values of x").

I think it's just pointing out the difference between '&' and '&&'.

The number of people who disagree on whether or not it's UB to begin with speaks for itself...
UB? I don't get the first one.
Googled it. I think he means undefined behavior.
Reading an uninitialized variable is UB.
Is it a local? I think the int declaration is for showing the type of x. It's just a code fragment as is.
Fair point, we don't have context.
No they don't. What UB do you think they invoke?

They do invoke implementation defined behaviour, but not undefined.

An uninitialized variable is UB, not implementation-defined. Thus, the compiler is free to treat the variable as though it doesn't have a value at all, or change it's value at will. It's not uncommon for the value of an uninitalized variable to change at strange places in the code that you wouldn't expect, because the compiler initially said "Variable x will be kept in register %eax", but then without a value to initialize it too, it just uses whatever happens to be in %eax at the time. For example, if they compiled this:

    return x == (1 && x);
Into this:

    movl $0, %eax
    andl $1, %eax
    cmpl %eax, %eax
    # Result in %eax
That will (obviously) return 1 every time, because we compare %eax and %eax. The reason for this is that the value of 'x' changes half-way through the computation (Because the computation is done in %eax, which is where 'x' is assumed to be). This is valid because 'x' is uninitalized, so it doesn't have a defined value.
What evidence do you have that it's an uninitialized variable?

It's a code fragment; it's not in a function body. The way I read it, it was simply to document the type of x. 'x' could be a global for all we know.

My evidence is that the entire page is basically just to shows CIL's output on various pieces of code, and CIL's output is linked on the page and looks like this:

    /* Generated by CIL v. 1.3.7 */
    /* print_CIL_Input is true */

    #line 1 "cilcode.tmp/ex30.c"
    int main(void) 
    { int x ;

      {
    #line 2
      return (x == (x != 0));
    }
    }
From that I think it's safe to say that it's talking about 'x' being an uninitialized variable in a function (Because that's what they put into CIL). This code definitely has the issue from UB that I described above.