General > General Technical Chat
How many people code in C these days, and if so, why?
SiliconWizard:
--- Quote from: Karel on May 11, 2020, 12:14:30 pm ---
--- Quote from: Nominal Animal on May 11, 2020, 11:21:31 am ---..., so much so that I actually prefer C99 over C11.
--- End quote ---
Can you give some examples of what you don't like about C11?
--- End quote ---
Also curious.
SiliconWizard:
--- Quote from: IDEngineer on May 10, 2020, 03:43:30 pm ---With respect to the use of booleans in C....
I'm a huge proponent of the style "if (boolean)" or "if (!boolean)" for several reasons. First, IMHO it's concise and clearly conveys what is being evaluated. YMMV.
Second, long ago I was analyzing the Assembly language output from a compiler and found that it generated different code depending upon how if statements were written. If I wrote "if (variable)" or "if (!variable)", it generated ultra-tight code by clearing the Z flag, pulling the variable into a register, OR'ing the register with itself which (might) set the Z flag, and then testing the state of the Z flag. But if I wrote "if (variable == true)" the compiler actually performed a comparison with an immediate value equal to "true" (or whatever value was specified), generating signficantly more Assembly instructions for the same net result.
Having learned this, I also started testing non-boolean variables for zero with "if (!variable)" which yielded smaller, faster code as described above. This was especially nice (and low cost) when checking for null pointers.
I lived in this blissful state for a very long time. THEN... my code started failing in weird ways on some project. So I dug into the Assembly generated by THAT compiler, and to my horror discovered that it did not generate proper Assembly unless a value was specified for the comparison! That is, "if (boolean)" and "if (!boolean)" generated BROKEN CODE but "if (boolean == true)" and "if (boolean == false)" did not. The != versions also generated proper code. The compiler simply demanded two explicit values to compare. I could not believe it, but I was trapped by the authors of that compiler. Once I rewrote my code to always provide a value against which to compare, it started working perfectly.
This is a long winded way of saying that despite agreeing it looks terrible and should not be necessary, I now write "if (boolean == true)" even though strictly speaking it is not necessary. I do so because that source code will always work with every compiler I've ever encountered, whereas I know there's a team out there somewhere that wrote a compiler where that would silently (e.g. without reporting an error, nor even a warning) generate broken code without the immediate value. Supporting two values with a comparison operator between them is so fundamental to the language that we can safely presume it will always work, so for reliability I now write that way. And I urge the universe to inflict terrible harm on that compiler team every time I do so.
--- End quote ---
I have personally never run into such a compiler bug. That would look like a bug on a *very* basic C feature, and said compiler should probably have never been trusted for anything else. But I know sometimes you just don't have a choice. (One bug I do remember from an old C compiler - IIRC it was cc on some old Solaris system - was an operator precedence bug. Writing something like 'if (a == b && c == d)' would not yield the proper condition, and you had to use parentheses to make it correct: 'if ((a == b) && (c == d))'. And I did grow an habit of always putting parentheses like this, even to this day. I also find it more readable. So I can relate.)
I still want to draw people's attention to the dangers of comparing C "booleans" with a constant.
As I said already, C considers 0 to be false as a condition, and non-0 to be true.
So 'if (boolean == false)' (assuming 'false' is defined as 0) is indeed guaranteed to always be correct and equivalent to 'if (! boolean)'.
OTOH, 'if (boolean == true)' is a terrible potential mess, since a *true* condition in C is not guaranteed to have any specific value (at least before C99), so depending on how you manipulate your "booleans", that kind of test may utterly fail. And it's not just theoretical: I've seen this done in existing C code and it introduced a major bug.
Sure if you always assign your "booleans" with constants and nothing else, that should be OK. (But still pretty clumsy IMHO.)
But if you assign some of your booleans with conditions, such as: 'boolean = a != b' (which is perfectly valid, and works in most programming languages actually), then you have a problem. Before C99, such a condition was not guaranteed to have a 0 or 1 value exclusively. And I've SEEN that not being the case with real compilers. (One low-level explanation would be that such an assignment would simply be implemented as a subtract operation in assembly.)
So, beyond the style question, I think you should be very careful with this.
Nominal Animal:
Why I prefer C99 (per n1256.pdf) versus C11 (per n1570.pdf)?
Instead of bringing portable, widely-implemented features like getline(), the standards committee was stuffed with Microsoft stooges who instead of furthering the C programming language, furthered the schemes of Microsoft by introducing the entirely unneeded Annex K. In other words, instead of getline(), you now have the "safe" fgets_s() instead. :palm:
None of the wide-character internationalization support got any enhancements, either. They are not needed, after all, because Microsoft does not actually support locales (without proprietary extensions) anyway.
(I was really hoping for getline() and getwline() to get standardized, because those two alone, taught to newbies, would remove a whole slew of typical bugs and inane limitations made by new C programmers. As it is, almost nobody localizes their C programs anymore; the standards committee has made it clear who commands it, and what direction it will be dictated in. A big reason is that standard code that is supposed to work even on Windows, doesn't, when the Windows' user locale uses UTF-8. Simply put, even after stuffing the C standards committee with people on their payrolls, they couldn't tweak the standard enough so that their own limpy implementation actually follows the standard.)
The immensely useful iconv_open()/iconv()/iconv_close() interface from POSIX did not get standardized, because Microsoft didn't want to implement it. To use it in Windows, one can install the libiconv library to get the support; basically all other desktop and server operating systems already incorporate it into their C library. But because Microsoft doesn't, it won't get into the C standard.
Instead of standardizing the atomic operations implemented by GCC, Intel Compiler Collection, and a host of other compilers (but apparently not Microsoft Visual C++, which is after all more important and equal than anything else) – noting that they were the second generation of such ops, the first being __sync built-ins, that AFAICR were originated in ICC, not GCC –, they went with their <stdatomic.h> approach, which may or may not provide some features (it is up to the implementation; although you can check it via the __STDC_NO_ATOMICS__ preprocessor macro), because that is the easiest way to implement minimal atomics support for a C++ compiler.
In C11, variable-length array support became optional, because one vendor's C++ compiler has issues with those.
Instead of leveraging existing POSIX threads with decades of C use, the committee went with a new "standard thread" support <threads.h>, whose actual compiler and OS support is unknown and iffy at best.
Instead of utilizing experience with POSIX clock_gettime() facilities, they farted out an timespec_get() whose support is, well, purely a guess. If you have ever written a benchmark or test program that uses both CLOCK_REALTIME and CLOCK_MONOTONIC clocks, you can immediately see why the timespec_get() interface really does not cut it.
Really, if we look at C11, the really good things it provided was the _Generic() selection expression and the _Thread_local storage class specifier!
Up to C99, the C standards committee had taken already implemented things with user experience finding them useful, and standardized them.
With C11, that changed. Microsoft had decided to use it for the same purpose it standardized OOXML: to eliminate the need of having to compete with actual C implementations, and to ensure their own single-architecture C++ compiler implementation would suffice. Simply put, they threw the C standard under the bus, because they had the money, and they thought it would help their business.
Today, if one wants to write portable C code, Windows environment is right out. Even their locale support and terminal UTF-8 input/output won't work without using Microsoft-only proprietary extensions. You will need to use predefined compiler macros to write Windows-specific code selected via preprocessor directives at compile time, if you do anything more complicated than a "Hello, world!" program. I'm sure Windows-only developers find this perfectly acceptable, but me, I do not want to be slaved to a single vendor. If a tool tries to restrict the portability of my code (like ICC did and does at runtime to code running under AMD processors), that tool goes out the window.
So, for portability and functionality, POSIX C (IEEE Std 1003.1-2008) and C99 is still the best bet. Not perfect by any means, but the best fit, for now. C11 and C18 could have continued the path that C99 started from C89, but instead, basically twisted the C standard into furthering the goals of a single vendor. As I understand it, C18 doesn't even add anything to C11 anymore, and is simply a collection of errata (because the day Microsoft gets something right the first time, is the day hell freezes over).
Okay, why the vitriol against Microsoft? It's not, really; it just happens to be the vendor that did this to the C standards committee, which allowed it to happen. If it had been Intel or Pathscale that did it (AFAIK IBM don't have their own proprietary C compiler anymore), I'd be equally disgusted with them. I'm angry at the entity that did this to the C standard development process. Microsoft today is, I believe, quite different as a company, but standards development stuff moves slowly, and it may be impossible to undo the damage done. There may not be sufficient interest to even try.
There is still hope that POSIX C continues to develop, although it remains to be seen. One can read IEEE Std 1003.1-2017 online here, and the list of C functions and interfaces is here.
Please do realize that I am looking at this as someone who really appreciates good tools, and gets immensely disgusted when someone fucks up the future of an existing tool. I feel the same way when a physical tool manufacturer sells their brand to a low-cost manufacturer, who exploits the brand for increasing short term profits. This can happen even during the lifetime of a product – sadly common with computer electronics, actually, except that none of the manufacturers have a particularly good reputation anymore.
I don't care if it is C, or something else; my attitude depends only on it as a tool for solving problems, or implementing other tools. If you feel that everything you do is already dependent on Microsoft – or some other single vendor, like IBM, who now own Red Hat and have immense (and not altogether positive, in my opinion) say in the direction desktop and server Linux operating systems (i.e., those running the Linux kernel) will take in the future – then good for you; my reasons here will be irrelevant to you, and you can safely ignore them. But, if you are someone who has been in the software business for three decades, give or take, and don't want to be dependent on a single vendor because they will eventually fuck you over, you'll understand why the direction change between C99 and C11 has reduced my expectations from the C standards committee to zero.
I guess I should apologize for the rant, but I don't wanna. Every point above is something that I have seen bite someone else besides myself. The locale support and getline()/getwline() facilities are a particular sore point, because even MS actually implements them in their base "C" library; but as it is, they are practically forgotten in current C software projects. That angers me, because it leads to bugs (buffer overruns) and inefficiencies or artificial limitations, that would have been so easy to avoid otherwise. :'(
SiliconWizard:
OK, I get some of your points.
Do you have actual proof MS influenced C11 in such a way? You seem very convinced of this.
As to threads, the support is optional in C11 AFAIR, and from the little I experimented with this, GCC implements it as a thin layer above PThreads actually. But I'm expecting support in other compilers to lag. A lot.
And yes, _Generic() is interesting. That's about the only thing I've ever used from C11 so far.
chriva:
If someone has the penguin as a profile picture you just know they'll hate ms in every way possible and even blame them for stuff they didn't do. The open source world have benefited A LOT from big corps too. Start looking for google and Microsoft mentions in the codebase of many free and mature projects.
It took Microsoft two tries. Shall we start on how many small tries it took independent developers to get things straight in their stuff?
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version