Hacker News new | past | comments | ask | show | jobs | submit login
P99: Preprocessor Macros and Functions for C99 and C11 (2012) (inria.fr)
55 points by fanf2 56 days ago | hide | past | web | favorite | 21 comments

I have the experience that to be truly compatible with everything that potential users of your code would like to use (embedded systems, ...) one still needs to write C90, what's your experience with this and where are C99 and C11 used the most?

(not the author) I'm writing my C headers in the "common subset of C99 that compiles both in C and C++ mode on clang, gcc and MSVC".

This subset is basically a post-C90, pre-C99 version of C which has most convenience-extensions which existed before C99, like declaring variables in the middle of a scope block, allowing to declare the loop variable inside for(), etc...

I tried to port my header libraries to "pure" C90, but I didn't enjoy programming at all in this. The mid-90's pre-C99 C is almost like a new language compared to ISO C90.

I'm using C for very small cross-platform programs targeting WebAssembly, e.g.:



MSVC was a pain until the 2015 version. Now writing C99 is safe if you target it. Microsoft did immense harm to the industry though, by not supporting C99 until recently. Many Windows-only programmers I saw not even aware of C99 and C11 features, sigh... Anyway, there is no reason to use MSVC at all. Both Google and Mozilla switched[1][2] to use clang-cl[3], which is a drop-in replacement for MSVC cl. Moreover, it supports various sanitizers - ASAN, UBSAN, etc for Windows platform. MSVC didn't even have support for inline assembly! A piece of crap, not a compiler. Just use clang-cl instead.

[1] http://blog.llvm.org/2018/03/clang-is-now-used-to-build-chro...

[2] https://blog.mozilla.org/nfroyd/2019/04/25/an-unexpected-ben...

[3] https://clang.llvm.org/docs/MSVCCompatibility.html

Interesting that your third link says they now have partial support for SEH (__try). That was a very big missing Windowsism for a long time.

I guess they never did C++/CX either, but that was a bit of a misadventure on MS's part and I don't see anybody pushing it anymore. (Maybe I just haven't been paying attention to those circles lately.) It's funny how many of the ambitious WinRT era initiatives accomplish buy-in at a rate outpaced by the diminishing relevance of the platform.

I actually prefer x64 VC++'s inline asm support to the gcc variety.

C99 support has been OK since VS2012 in my experience. Library support was iffy in earlier versions, but anybody accustomed to actually writing multi-platform code could handle it. A bit of a silly situation, but, as always, if you need to target multiple systems, you just do what you have to.

Luckily, you can now probably rely on VS2015 or better.

> Microsoft did immense harm to the industry though, by not supporting C99 until recently.

That's overblown. I don't use C99 myself, other than the odd library function. I don't like most of the C99 and C11 features.

I was following ISO C very closely in the time frame surrounding C99; but I lost interest in ISO C as such after that disappointment.

Designated initializers are very important. As a maintainer of a codebase that has to support older Windows OSes and MSVC releases, I still suffer from not being able to use them.

Really, GP is correct, MSFT did immense harm by not implementing more/all of C99 sooner. I'm still quite annoyed by that even now, even now that MSFT has finally started doing amazing things.

> Designated initializers are very important.

I use macros or functions to initialize structures. When a new member is added that must be initialized to a non-default value, I can add a parameter to the intializer, and then the compiler finds all the places where an argument must be added.

I could easily work this gradually into an old code base that I have to maintain.

Such an initializer macro can be implemented itself using designated initializers, but that is of low value; it's in one place, next to where the struct is declared.

The designated initializer clearly wins if we have to declare a large, sparse array without executing code, and initialize just a few entries to nonzero which are not close to the beginning.

If you're using cscope/etags/an IDE then you want the field name to be visible where the assignment is made, otherwise finding your way around a codebase with many function dispatch tables can get painful.

I have a macro or function name that occurs wherever the struct is initialized.

  struct point p = point_init(x, y);
ctags will find the definition of point_init, and cscope all the occurrences.

Random code throughout the program that is not related to the data type's module shouldn't be performing explicit low-level member-for-member initializations of the data type, even with a safer mechanism like designated initializers.

Yes, but if you have a struct with many functions then you still have a problem. With designated initializers I can traverse all the paths through cscope alone.

I can't even begin to imagine a foggy gist of what you might be talking about, but it seems very real to you.

I should do an asciicinema thing, I guess. Point is, I can search for assignments to any one function-typed fieldname of a struct and find all the functions that are reachable through instances of that struct.

Are we (still) talking about C here? Initialization isn't assignment in C; structure elements are called "members" and they cannot be functions.

The common subset of C99 that compiles in both C and C++ is basically "C90 with // comments".

There are many more, though what comes immediately to mind are variadic macros and long long. (Actually, here's a good list: https://stackoverflow.com/questions/47524553/are-all-of-the-...)

Are there any widely used C++ compilers that don't also have a C personality? I've only ever worried about C++ compatibility in my headers. IME C and C++ toolchains make it relatively trivial to build and link C and C++ units together. However, I don't have much experience in the commercial embedded space (as opposed to x86 appliance "embedded"), which I've assumed were mostly C shops.

For single-file libraries (declaration and implementation in one header) it's sometimes more convenient to include the header implementation into a C++ file (and not compile the implementation in a separate C file).

Also, compiling C code in C++ mode might trigger a couple more warnings which are actually bugs.

But these are the only reason I can think of compiling C code as C++.

> Are there any widely used C++ compilers that don't also have a C personality?

All of them. If you mean "aren't accompanied by a C compiler front-end also", that's something else.

If you want that C++ compiler's opinion about your code, then you have to pass it to the C++ compiler, not to its C cousin that has tagged along.

Try working a while with the strict ISO-C90 / C89 standard enforced in the compiler, it's tons of small (and some not so small) differences. With the usual clang/gcc extensions most of the pain points had been fixed long before C99 came along though.

Doesn't it need a (2012) tag? Also where's the code I can download?

Source is available here: http://p99.gforge.inria.fr/

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact