1

I'm trying to work with some legacy C89 code, and am having trouble getting it to build. My usual environment is Visual Studio, but that only seems to support C99, and some C99 features (such as stdio etc. not necessarily being constant) break the code - a lot. Before I start tampering with the code I want to write some tests, so I don't break the old behaviour, but I can't test the tests, so to speak, before I can get the code to build.

So is there still any way to compile C89 code on Windows?

Edit: Steve Summit has identified that stdio and so on has never been guaranteed; it's just a feature of some compilers that my legacy code happens to depend on, in a rather deeply embedded way. So my question shifts to whether there is any Windows C compiler available (preferably free!) for Windows that supports that assumption. Alternatively, I have an Ubuntu installation in a virtual machine, although I have little experience using it - is there such a compiler available in Ubuntu?

digitig
  • 1,989
  • 3
  • 25
  • 45
  • http://www.mingw.org/ is a port of gcc for MS, compile using `gcc -std=c89 -o app.exe source.c` – David Ranieri May 22 '19 at 14:18
  • 2
    Can you show a C89 [mcve] you're having trouble with? – Jabberwocky May 22 '19 at 14:19
  • 5
    If anything, that should be the other way around - VS doesn't fully support C99, so it may fail to build code using C99 features, but it should be rock solid on C89 code. What build errors are you getting? Are you sure it's being compiled as C and not C++? Are you sure you have all the code you need? – John Bode May 22 '19 at 14:26
  • 3
    MSVC is not a conforming C99 compiler. It does not conform completely to C89, either, but its deviations on that side are small and somewhat obscure. If building puported-C89 code in MSVS (in C mode, not C++ mode) fails or produces a misbehaving executable, then chances are good that it is the program that is broken, not the compiler. – John Bollinger May 22 '19 at 14:26
  • 3
    "such as stdio etc. not necessarily being constant" Que? – Lundin May 22 '19 at 14:27
  • @Lundin I'm guessing that meant "`stdin` etc. not necessarily being constant". – Steve Summit May 22 '19 at 14:33
  • @SteveSummit How is that any clearer though? What is a "constant header"? – Lundin May 22 '19 at 14:35
  • I make no sense out of it still. – Lundin May 22 '19 at 14:39
  • 3
    The good news: Microsoft are 20 years behind every other C compiler on the market. They only have partial support for C99 still. Their C compiler mostly follows C90. The bad news: Visual C has bad conformance to _any_ C standard. It is to be regarded as a C++ compiler with some sloppy, partial support for C on the side. – Lundin May 22 '19 at 14:40
  • @Lundin see the "answer" I just posted. – Steve Summit May 22 '19 at 14:44
  • Yes, I meant stdin (and stdout, and stderr) being constant. And Lundin: the Googling I did before asking the question indicated that Microsoft attributes stdin, etc, not being constant directly to C99 implementation. So 20 years behind is still too recent. – digitig May 23 '19 at 02:10
  • regarding initializing stdin there are a lot of duplicates: [Error initializer element is not constant](https://stackoverflow.com/q/7623735/995714), [FILE * ..=stdout : Error initializer element is not constant](https://stackoverflow.com/q/35596220/995714), [Initialize a `FILE *` variable in C?](https://stackoverflow.com/q/50430284/995714) – phuclv May 25 '19 at 16:16

3 Answers3

3

MSVC is a C++ compiler and has just gained C99 support recently. Previously it supports only C89 with some MS extensions. To compile in strict C89 mode use the /Za option. Make sure to also enable /Tc to use C mode

/Za, /Ze (Disable Language Extensions)

The /Za compiler option disables and emits errors for Microsoft extensions to C that aren't compatible with ANSI C89/ISO C90. The deprecated /Ze compiler option enables Microsoft extensions. Microsoft extensions are enabled by default.

See Enforce ANSI C Standard in Visual Studio 2015

Most other compilers use other options like -ansi, -std=c90 or -std=iso9899:1990


However if this is just about stdin/stdout not being constant while using in a static initializer list then it's completely irrelevant to C89 and is actually an XY problem. The following snippet compiles without problem in VS2019 C++ mode, so if you don't have any possible conflict just compile the code in C++ mode

#include <stdio.h>
FILE* ifp = stdout;
int main()
{
    fprintf(ifp, "test\n");
    return 0;
}

Otherwise it's easy to fix that to compile in C mode by moving the initialization into main()

FILE* ifp = NULL;
int main()
{
    ifp = stdout;
    fprintf(ifp, "test\n");
    return 0;
}
Community
  • 1
  • 1
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • I don't see anything wrong with it, but it doesn't solve my problem, because the assumption of the standard streams being constant is woven throughout the legacy code and will be tricky to unravel. – digitig Jul 03 '19 at 00:26
  • @phuclv is there somewhere a list of the C99 extensions Visual Studio supports in C99? – FlashMcQueen Dec 03 '20 at 08:34
2

[This isn't really an answer, but it's too elaborate for a comment.]

If you've got code that does things like

#include <stdio.h>
FILE *ifp = stdin;
int main() { ... }

and if the problem you're having is errors stating that stdin is not a compile-time constant suitable for a static initializer, I think you're going to have to rewrite that aspect of your code. I could be wrong, but if I remember correctly, the idea that stdin et al. were compile-time constants was never a guarantee, just a useful property of the earliest Unix implementations. It wasn't necessarily true of all old implementations, so the "change" to the Standard that explicitly said they weren't necessarily constant wasn't a change per se, but rather, more or less a codification of the divergence of existing practice.

(In other words, if you've got a compiler that's rejecting the code, and even if it has a backwards-compatibility mode, I'd be surprised if the backwards-compatibility mode turned stdin into a compile-time constant.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • There's no guarantee that stdin is a compile-time constant in any version of C and it has not changed since C90. The standard just says it is of type `FILE*`. – Lundin May 22 '19 at 15:00
  • That's exactly the main issue I'm getting - many many times, across multiple files and buried in data structures, so rewrite probably isn't a good idea - I've nothing to test the rewrite against. It looks as if I need to find a compiler that does support that assumption. – digitig May 23 '19 at 01:41
  • @digitig: Some platforms may use data structures for file handling that map nicely to `FILE*`, but which do not determine where `stdin` will be until the program is executed. While it would be possible for an implementation targeting such a platform to make `FILE*` be a wrapper around the implementation's internal type, doing so would mean that modules compiled with that implementation would be incompatible with those compiled using others. That may be a worthwhile trade-off for some purposes, but not one that I would particularly expect implementations to support. – supercat Jun 16 '19 at 20:03
1

All supported (and even older) versions of Visual Studio are perfectly capable of compiling C89 code. Also C99 is backward compatible with previous revisions of the language, so a C99 compiler should be able to compile just fine C89 code.

Although you might get some warnings, the code should compile and work just fine if the code is portable of course.

phuclv
  • 37,963
  • 15
  • 156
  • 475
The Storm
  • 71
  • 8
  • 2
    "Perfectly capable" -> "somewhat capable, maybe". But hey, we support gcc too. – Lundin May 22 '19 at 14:41
  • 1
    A better option for alternative Windows compiler is clang, because of it's binary compatibility with the MS libraries. :) Also I haven't met a C89 portable code that the MS compiler can't compile. – The Storm May 22 '19 at 14:49