Code Behaving Differently In C90, C99, C11, C++98, And C++11

Hacker News new | past | comments | ask | show | jobs | submit login
Code behaving differently in C90, C99, C11, C++98, and C++11 (kristerw.blogspot.com)
134 points by Kristine1975 on July 24, 2016 | hide | past | favorite | 17 comments
pcwalton on July 24, 2016 | next [–] I think this goes to show that theoretical backwards compatibility doesn't matter nearly as much as de facto backwards compatibility. As this IOCCC entry shows, every single C++ revision has been a breaking change to the previous revision. A naive interpretation of this would say "well, C++ is not useful for enterprise use because the language is constantly changing". But in reality it doesn't matter, because the backwards-incompatible parts affect code nobody would intentionally write (excluding IOCCC entries!), and as a result C++ has a deserved reputation for stability.

vmarsy on July 24, 2016 | parent | next [–] > As this IOCCC entry shows, every single C++ revision has been a breaking change to the previous revision

This post never mentions C++'s backwards compatibility. It points out these 3 examples:

// comments C90 does not have // comments, so constructs of the form ...

i.e. more recent version of C and C++ is a super set of C90 here, but writing valid C90 (without using // comments), would compile file in C90 and above.

Wide string literals C11 and C++11 have wide string literals where for example U"hello!" Same reasoning for these, you would never use U"hello!" in pre C11/C++11.

The 3rd example is a fundamental difference between C and C++:

Character constants, such as 'a', have type int in C while C++ use the type char. This means that sizeof('a') evaluates to a different value for C and C++. This is not about backward compatibility, backward compatibility means : your code written in C++98, still works if compiled in C++11, it does not say : "write code using newer C++98/11/.../ and try to compile it in a previous version (or a different language) and see what happens."

To an extreme it's like saying:

template<class A> struct foo { // some methods with use of lambda, variadic templates, ... }; "Hey look, the above example doesn't work with C++98, C++ backward compatibility is a myth!"

chx on July 24, 2016 | root | parent | next [–] You contradict yourself:

> backward compatibility means your code written in C++98, still works if compiled in C++11

> writing valid C90 (without using // comments), would compile file in C90 and above.

Aye. There's the rub: backwards compatibility is broken by introducing // as int i = 2 //* */2 which is perfectly valid code in C90 evaluates to 1 while 2 in later version. When releasing later versions you are always breaking someones insane code. It's a matter of compromises between breaking 0.00000000001% of the codebase and progress. The number of zeroes in that percentage is of course debatable, see http://www.cl.cam.ac.uk/~pes20/cerberus/notes50-survey-discu... where a number of "Do you know of real code that relies on it?" are answered by ~20% of yes and ~20% of no, that would be crazy. So it is entirely possible the standards committee believes a construct is not used, that'd be crazy but it actually is used.

ben0x539 on July 24, 2016 | root | parent | next [–] no version of C++ ever added new comment syntax that a previous version of C++ didnt have, tho

Someone on July 24, 2016 | root | parent | next [–] Nitpick: as far as I can tell that's _almost_ correct.

http://www.softwarepreservation.org/projects/c_plus_plus/ind... leads me to http://www.softwarepreservation.org/projects/c_plus_plus/cfr..., which shows that the first external C++ release didn't have // comments.

The first commercial release had, though (http://www.softwarepreservation.org/projects/c_plus_plus/cfr...)

ben0x539 on July 24, 2016 | root | parent | next [–] Darn. :P

I was only thinking of the standardized ones, but you're correct, of course!

ajenner on July 24, 2016 | root | parent | prev | next [–] > you would never use U"hello!" in pre C11/C++11.

I have seen real world code which does almost exactly that and which broke (fortunately with a compiler error rather than silently changed code) when compiled with a C++11 compiler due to the new user-defined literal syntax. I agree that it's rare, but it can happen.

Asooka on July 24, 2016 | parent | prev | next [–] Except you can perfectly well link together a C89 and a C++11 object file compiled with the same compiler. All compilers let you specify the exact standard you're compiling, so even if tomorrow C++2x adds "frob" as a keyword, you can opt out of it in most of your code and only compile a few of your .cpp files as C++2x and they will still link together just fine because the ABI is stable.

Which means you're never in the position that "this update broke our code", barring of course compiler bugs and switches to a new ABI, both of which are extremely rare.

comex on July 25, 2016 | parent | prev | next [–] My experience is that a lot of really old C++ code fails to compile on modern compilers - generally not because of new standards, but because the compiler(s) the code was written against didn't enforce the standards of the time properly (especially old versions of GCC). C++ has been around a pretty long time though.

tmzt on July 24, 2016 | parent | prev | next [–] It would be good to avoid this same kind of thing in Rust, even with official versioning policies there have been many releases which change things that are "unlikely to cause issues."

pcwalton on July 24, 2016 | root | parent | next [–] I'm actually arguing the exact opposite. It's better to make changes that fix obvious issues that don't break anything in practice rather than to adhere to some academic notion of "complete" backwards compatibility.

tmzt on July 25, 2016 | root | parent | next [–] Right. By "this kind of thing" I mean code that breaks subtly like the examples in the article. I don't mean to argue with the breaking changes (versus the 1.0) in Rust which have been well thought out. Just that an accumulation of these types of changes without an errata of sorts on 1.0 Rust could lead to something like this down the road.

gpderetta on July 24, 2016 | prev | next [–] Because of SFINAE for expressions added in C++11 (which gives the capability to test at compile time whether an arbitrary expression is valid or not), technically any change to the language or standard library can change the behaviour of a valid C++ program.

pveierland on July 24, 2016 | prev | next [–] One behavioral change in C++11 is the noexcept specifier; with user-defined destructors defaulting to noexcept(true). If you have pre-C++11 code throwing exceptions from within a destructor, e.g. to signal a violated postcondition contract, the program will terminate when such an exception is thrown after compiling the program as C++11.

Updating the code to function under C++11 requires adding a noexcept(false) specification to throwing destructors.

bluejekyll on July 24, 2016 | prev | next [–] This is really cool. Though, I have to say, I was hoping that it was examples of undefined behavior and how that changes between versions and compilers.

But still, pretty neat in terms of features.

omoikane on July 25, 2016 | prev [–] Summary of all tricks used can be found here: http://uguu-archive.appspot.com/fuuko/source/c_version.c

Kristine1975 on July 25, 2016 | parent [–] And http://ioccc.org/2015/yang/spoiler.html contains a Javascript-based replay of the author writing the program. From an empty editor window to non-obfuscated code to the ASCII art face.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact Search:

Từ khóa » C99 Vs C11 Vs C90