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 :-)
A glimpse of undefined behavior in C
41–50 of 67 posts
Re: A glimpse of undefined behavior in C
#42Earlier 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…
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
#43Lesson 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
#44The 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…
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
#45Lesson I took away: The ++ operator should be deprecated except when it's the only operation on that line.
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
#46The 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…
Re: A glimpse of undefined behavior in C
#47Earlier 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…
Re: A glimpse of undefined behavior in C
#48Earlier 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.
Re: A glimpse of undefined behavior in C
#49Isn't this actually called "implementation-defined" behaviour in the std rather than "undefined" behaviour? I generally get a segfault for undefined behaviors
You can never rely on your compiler's implementation of undefined behavior.
Re: A glimpse of undefined behavior in C
#50Not "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.