Live data from Hacker News

A glimpse of undefined behavior in C

blog.chris-cole.net

41–50 of 67 posts

Re: A glimpse of undefined behavior in C

#41
I observed this when I was back in school using a simpler expression i = 0; i = i++;

the answer will be different in different compilers. I use this as an interview question ever since, not to get the right answer but to understand the candidates thought process in solving the problem and his/her understanding of operator precedence :-)

Re: A glimpse of undefined behavior in C

#42
post #32

Earlier quoted context omitted.

Practically every new version of gcc adds a new optimization that recognizes some new form of undefined behavior and then rewrites your function to do whatever it wants. Classic example: signed integer overflow. It worked for decades. Then one day it didn't. If you want to know about this particular example: https://news.ycombinator.com/item?id=6824514 (not personally confirmed)

That isn't really an accurate description of the issues: it's not the case that it was "working" and then "broken" by GCC maintainers. It's always been unsupported and not worked in specific situations, but for 99% of code it appeared to GCC users that it was supported. The signed integer overflow behaviour was never guaranteed by old versions of GCC, and code exploiting it would not always be compiled with the "expe…

That is my point. De facto working code is not working code.

I have fixed feelings about the integer overflow issue because it's so easy to trigger, unlike triple post increment fake examples. And it usually results in a security problem. For very little benefit, IMO.

Re: A glimpse of undefined behavior in C

#43
post #38
post #29

Lesson I took away: The ++ operator should be deprecated except when it's the only operation on that line.

I think users of for/while loops will disagree. Don't forget that =, += , ... can all be abused in the same way.

    (int i=0;i
would count as three lines for purposes of that rule, and the

    i++
as one. I could have been more precise, but I thought it would be understood.

The point is, to be on the safe side, don't use ++/-- in any line (in the sense of ;{}-delimited statement) that is also doing something else.

>Don't forget that =, += , ... can all be abused in the same way.

I didn't, and people should use the same safeguards around them, i.e. don't mix them within lines that do other things, "cleverness" or "C golf" be damned.

Re: A glimpse of undefined behavior in C

#44
post #34

The way I learned that in C a long time ago was "post increment" was "post statement increment".

There was a popular myth way back in the 90's that preincrement was always faster than postincrement because the former could generate a temporary. As if this were the case: /* x++ */ inline int postincrement(int *x) { int temp = *x; *x = *x + 1; return temp; } /* ++x */ inline int preincrement(int *x) { *x = *x + 1; return *x; } But in typical usage, where the expression value is not used, it doesn't make any differ…

I was actually asked in an interview at Google in 2011 whether pre- or postincrement was faster in a snippet of code where the expression's value wasn't used. When I said that I was pretty confident that the compiler would produce the same assembly in both cases, the interviewer insisted that pre- was faster based on the same logic you mentioned.

To her credit, she didn't penalize me for disagreeing with her and I still got the offer.

Re: A glimpse of undefined behavior in C

#45
post #29

Lesson I took away: The ++ operator should be deprecated except when it's the only operation on that line.

I like using it when I'm filling an array with an indeterminate number of elements. I've used this pattern a few times:

    foo foos[255];
    int ct = 0;

    if ()
        foos[ct++] = foo1;

    if ()
        foos[ct++] = foo2;

    ...

    for (int i = 0; i 
IMHO, this is more concise and readable than separating the increment and assignment into two lines.

Re: A glimpse of undefined behavior in C

#46
post #34

The way I learned that in C a long time ago was "post increment" was "post statement increment".

There was a popular myth way back in the 90's that preincrement was always faster than postincrement because the former could generate a temporary. As if this were the case: /* x++ */ inline int postincrement(int *x) { int temp = *x; *x = *x + 1; return temp; } /* ++x */ inline int preincrement(int *x) { *x = *x + 1; return *x; } But in typical usage, where the expression value is not used, it doesn't make any differ…

This is one of those things I've had in my head for years, and as a result of this I habitually use pre-increment in code, even in other languages. I think I haven't actually believed the "myth" myself, though, for quite a while.

Re: A glimpse of undefined behavior in C

#47
post #39
post #34

Earlier quoted context omitted.

There was a popular myth way back in the 90's that preincrement was always faster than postincrement because the former could generate a temporary. As if this were the case: /* x++ */ inline int postincrement(int *x) { int temp = *x; *x = *x + 1; return temp; } /* ++x */ inline int preincrement(int *x) { *x = *x + 1; return *x; } But in typical usage, where the expression value is not used, it doesn't make any differ…

I always thought this "myth" was confined to C++ code (iterators) where there may in fact be code that does something analogous to what your "postincrement()" does. Compilers are sometimes smart enough to remove the unnecessary operation in C++ (e.g. switch to ++x themselves), but I always use ++i for the same reason people simplify their usage of C in between sequence points --- it's an easy transformation, and why…

The compiler can't necessarily optimise i++ away in C++, because the ++operator or the destructor of the temporary iterator object returned may have side effects. It's still not quite equivalent to ballards postincrement() though, because the C++ standard allows for that temporary copy operation to be optimised away

Re: A glimpse of undefined behavior in C

#48

Earlier quoted context omitted.

I am not 100% sure in how they work either (haven't programmed C for 4 years), so I just avoid these kind of unnecessary complications in the code Hear, hear. I am considered the "language lawyer" of my embedded group and often get asked questions about C minutiæ. It isn't uncommon that my answer is "I don't know how that works, because I would never write something that requires an answer to that". Modern compilers…

Const-ness is really different. It's a concept I really miss from other languages as it _adds_ more semantic information to the code. It does not obscure, it clarifies. It's a way to give orders instead of giving recommendations.

I really liked const-ness as well; in functional languages const-ness comes for free as all state is by default immutable -- one the reasons I jumped to Scala.

Re: A glimpse of undefined behavior in C

#49
post #33

Isn't this actually called "implementation-defined" behaviour in the std rather than "undefined" behaviour? I generally get a segfault for undefined behaviors

It's undefined. That means the compiler and runtime can choose to segfault, do something that looks right, silently corrupt your program, launch the nuclear missiles, whatever. And there's no requirement that this behavior be repeatable, so the code can work with debug flags turned on but fail in a release build.

You can never rely on your compiler's implementation of undefined behavior.

Re: A glimpse of undefined behavior in C

#50
post #21

Not "well-defined" is the proper terminology.

No. You might be right if we were talking about "proper use" in English as a spoken language, but "undefined behavior" is a technical term defined by the C and C++ ISO standards.

I see, okay did not know "undefined behavior" was part of ISO. It's pretty unfortunate that I have to pay $30 to see the ISO standard...

http://isocpp.org/std/the-standard

Post reply on HN