Hacker News new | ask | show | jobs
by jussij 2300 days ago
> Note, I'd like my C code to work on Windows, which possibly restricts the "right way" to features provided by C89

That might be the case if you plan to use the Microsoft C compiler as they have publicly said the don't have plans to update their C compiler.

However that is not your only option, since clang and several GCC ports will also work on Windows.

2 comments

Microsoft has started to implement more of C99 over the years. I think it was 2015 where they implemented mixed declaration and code. I noticed they put stdint and stdbool finally in 2010 or so.

Still pretty incomplete last I checked but portability is better than it was.

Those features are based on ISO C++ requirements, regarding the adoption of underlying C features and respective standard library.
Mixed declaration and code is very old in C++, and Microsoft has always supported it there. It wasn't until vs2015 that they let you do it in a .c file.
Sure they did let do it, as long as that C file as compiled as C++.
There is a "C language mode" inside cl.exe (by file extension or by /TC flag) and there's plenty of C that doesn't compile as C++.

eg.:

   char *p = malloc(n);
No explicit casts from void*!

Anyway, around the time they started allowing mixed declarations and code in a .c file, I was noticing on-the-job that this was becoming a disproportionate source of build failures in intended-to-be-portable .c files my colleagues were writing on Unix. It was as if cultural memory of pre-C99 declaration requirements was disappearing specifically around that time. So it makes sense to me that they went ahead and added it. They probably got a lot of complaints.

Are you not able to use their C++ compiler to get modern features? My understanding is that C++ is a superset and that a C++ compiler is also usually a C compiler. Is this view incorrect for modern implementations?
It's not strictly a superset, to the point that there are good reasons to stay with a C compiler other than to simply stay sane. I make a lot of use of designated initializers for laying out static const arrays. And I actually don't like the way that structs in C++ can be referred to both with and without the struct tag. I also don't like how void-pointers are not compatible with other pointers without an explicit cast. Or that plain integers cannot be assigned to enum types. Some of this is just my personal preference (or Stockholm Syndrome), but the fact is that most C code will fail to compile as C++ without some changes.

MSVC is probably pretty close to C99 these days. Designated initializers are C99, for example.

You can assign integers to enum in C++, just like in C, but not to enum class. Use the latter when you need type safety, the former when you need to easily convert integer <-> enum, which apart from (de)serialisation is rare in my experience. And even in those cases, I personally prefer the explicit casts.

As far as I know, MSVC just implements the C subset of C++.

What I mean is this:

    > enum Foo { A, B, C };
    > Foo x = 1;
    test.cc:2:9: error: invalid conversion from ‘int’ to ‘Foo’ [-fpermissive]
     Foo x = 1;
I prefer not to use explicit casts because 1) using enum types is confusing to me 2) I frequently use values that are not in the enum - most often that's -1 as a way to indicate "missing". 3) I also like to iterate over all values from an enum using a plain for (int i = 0; i < NUM_FOOS; i++) without any fuss.

> As far as I know, MSVC just implements the C subset of C++.

There are things that work in MSVC C mode that do not work in C++ mode.

C++ is not a strict superset of C anymore. You can't compile all C in a C++ compiler.
has c++ ever been a strict superset of c?

afaik,

  int* arr = malloc(sizeof(int));
has never worked in c++.
It's probably never been a strict superset really.
To use a trivial example:

    int free;
care to explain which language this doesn't work in (and why)? I'm curious. AFAIK, `free` isn't a keyword in either language and this is just declaring an int variable with a legal identifier (but not initializing it).