Is it possible to compile C89 code on MS Windows? - c

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?

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;
}

[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.)

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.

Related

What are Vectors and < > in C?

I was looking at the source code for gcc (out of curiosity), and I noticed a data structure that I've never seen in C before.
At line 80 and 129 (and many other places) in the parser, they seem to be using vectors.
80: vec<tree> incomplete_record_decls;
129: ridpointers = ggc_cleared_vec_alloc<tree> ((int) RID_MAX);
I've never encountered this data type in C, nor these: < >. Are they native to C?
Does anyone know what they are and how they are used?
Despite the .c filename, this code is not valid C; it is C++, using that language's template feature. If you inspect the gcc build process, you will find that this file is actually compiled with a C++ compiler.
https://gcc.gnu.org/codingconventions.html
The directories gcc, libcpp and fixincludes may use C++03. They may also use the long long type if the host C++ compiler supports it. These directories should use reasonably portable parts of C++03, so that it is possible to build GCC with C++ compilers other than GCC itself. If testing reveals that reasonably recent versions of non-GCC C++ compilers cannot compile GCC, then GCC code should be adjusted accordingly. (Avoiding unusual language constructs helps immensely.) Furthermore, these directories should also be compatible with C++11.
Keep in mind that although compilers will usually by default infer a source file's language from its filename, this default can always be overridden. It is entirely possible to have C++ code in a .c file, or C code in a .bas file for that matter; you just may have to tell the compiler some other way what language is in use.
I expect that gcc chose this file naming convention because this code was originally written in C and later converted to C++, and they found it too much of a pain to change all the filenames. It would mean a lot of work to update all the makefiles, etc. It may have been less of a pain to just change which compiler was used, and to explain the convention to all the developers. Of course, in general it is better programming practice to name your files in the standard way, but apparently the gcc developers felt it was not the best course of action in this case.
GCC has moved from C to C++ since GCC 4.8
GCC now uses C++ as its implementation language. This means that to build GCC from sources, you will need a C++ compiler that understands C++ 2003. For more details on the rationale and specific changes, please refer to the C++ conversion page.
GCC 4.8 Release Series - Changes, New Features, and Fixes
The work has actually begun long before that, with the creation of gcc-in-cxx branch. The developers first tried to compile the source code with a C++ compiler, so there weren't any name changes. I guess they didn't bother to rename the files later when merging the two branches and officially have only one C++ branch
You can read GCC's move to C++ for more historical information

Using non-standard functions in Code::Blocks

I got this book "Beginning C" by Ivor Horton and I'm half way through it and I like it; so far so good. I use Code::Blocks on Windows as my IDE, and now I've run into the problem I cannot solve for about 3 days now.
The author mentions some "optional" functions in <string.h>, like strnlen_s(), and also says that these are available in the new standard — C11 (the book is from 2013; I don't know how new C11 actually is), and he also gives a piece of code that will determine "whether the standard library that comes with your C compiler supports these optional functions".
This is the code:
#include <stdio.h>
int main(void)
{
#if defined __STDC_LIB_EXT1__
printf("Optional functions are defined.\n");
#else
printf("Optional functions are not defined.\n");
#endif
return 0;
}
So I run the code to check if GCC in Code::Blocks does and determine that it doesn't. The book didn't recommend the compiler nor the IDE; I picked up Code::Blocks with GCC on my own, since that's what I do my exams in at college, so I figured I should get familiar with the environment.
The thing is, I have no idea how to "fix" this, since strnlen() doesn't work, strnlen_s() doesn't work, and bunch of others, and I can't really continue through a book. Not that I need them, or that I can't do it any other way (strlen() works just fine) but it would be nice to know how to use non-standard functions.
Up to date versions of GCC certainly do support C11, you need to enable it with the compiler flag -std=c11.
I presume you're using some flavour of MinGW with Code::Blocks - I recommend using MinGW-W64 as it is actively maintained and very up to date.
Also, bundled toolchains of MinGW-W64's gcc are available at TDM-GCC.
The Code::Blocks IDE itself doesn't care which version of C you're using, that doesn't affect what libraries you have available.
You are speaking of the optional Annex K Microsoft pushed through.
K.2 Scope
1 This annex specifies a series of optional extensions that can be useful in the mitigation of
security vulnerabilities in programs, and comprise new functions, macros, and types
declared or defined in existing standard headers.
2 An implementation that defines __STDC_LIB_EXT1__ shall conform to the
specifications in this annex.380)
3 Subclause K.3 should be read as if it were merged into the parallel structure of named
subclauses of clause 7.
It is generally seen as deeply flawed, and Microsoft trying to force it's use as a severe nuisance.
That's especially the case as they are the only major player implementing them, and their versions are non-conformant.
glibc with gcc for example provide most supposed advantages of that annex without introducing new functions, discouraging use of half the standard-library and forcing such a cumbersome API on programmers.
You might want to read the C tag-wiki, and especially grab a draft of the C11 standard (which is from 2011, as the name should imply).
The optional Annex K from the C11 Standard is not widely adopted yet (see Deduplicator's comment below). For instance as of February 2015 it hasn't been merged into glibc.
The good news is that you might try an alternative compiler. For instance Pelles C for Windows is a modified LCC with enhanced support for newest C11 features (like atomics and C11 threads model, that I believe are also mentioned in your book). Here is some basic program, that compiles and runs in it:
#include <stdio.h>
#include <string.h>
int main(void)
{
#if defined __STDC_LIB_EXT1__
printf("Optional functions are defined.\n");
#else
printf("Optional functions are not defined.\n");
#endif
char *str = "Hello Annex K";
printf("%zu\n", strnlen_s(str, 5));
return 0;
}
Output is:
Optional functions are defined.
5
Press any key to continue...

MinGW compiler doesn't need function declarations?

I have these two files:
// first.c
int main(void) {
putint(3);
}
and
// second.c
#include <stdio.h>
void putint(int n) {
printf("%d",n);
getchar();
}
When I run gcc 4.6.1 under Win XP:
gcc first.c second.c -o program.exe
It has no problem and writes 3 to stdout. It doesn't need putint declaration in first.c. How is this possible? Is this standard behavior?
I have tested this on MSVC 2008 Express and it runs only with the declaration as expected.
// first.c
void putint(int);
int main(void) {
putint(3);
}
Solved, thanks for hints, these options helped to show the warning:
-Wimplicit
-std=c99 (MinGW 4.6 still uses gnu90 by default)
This is a legacy "feature" of C that should not be used as of several decades ago. You should use a compiler with settings that will warn you if you do something like this. Gcc has several switches that you should specify when using it & one of them will give you a warning for this.
Edit: I haven't been using gcc myself, but switches that you should check out are -pedantic, -Wall, -Wextra, and -std.
The compiler that is accepting this is assuming, per the old language definition, that since you didn't see fit to tell it otherwise, the function a) returns an int value and b) since you pass it an int (or if you passed it something that could be promoted to an int) the function expects that argument to be an int.
As #veer correctly points out, this should generally work in your particular case. In other cases, however, differences between the implicit assumptions for a function without a prototype and the function's actual signature would make things go boom.
This isn't just for MinGW, but all standard versions of gcc. As noted, this is legal in C89; gcc defaults to 'gnu89' (not 99), which also accepts the code without warning. If you switch to c99 or gnu99 (or later, such as c11) you'll get a warning by default, but it will still compile.
As is noted by others, this is standard behavior for C conforming compilers. Naming your files .c partially puts it in C mode. It'll have fun things like "built-in functions" (printf() etc.) and all sorts of legacy C things.
I'd like to add to what others have said that I experienced recently, though. MS expressly dropped support for C past C90, and their C90 support is poor to say the least. I'm not entirely sure standard ANSI C90 codebases would compile under newer VS's, because it is basically the C++ compiler with lots of stuff disabled (whereas GCC actually has a C compiler). They did this in order to promote C++. If you want to use real C, you can't really do it in MS Visual Studio, any edition, unless you want to be declaring all your variables at the start of functions, etc.

plain c using new keyword

Overview:
I'm working with a hobby app. I want my program to be able to stick to "plain C".
For several reasons, I have to use a C++ compiler, and the related programming enviroment program, that supports "Plain C". And, for the same reasons, I cannot change to antoher compiler.
And, there are some C++ features that I have been coded, unintentionally.
For example, I'm not using namespaces or classes. My current programming job, is not "plain c" or "c++", and I haven't used them for some time, so, I may have forgotten which stuff is "plain c" only.
I have browsed in the internet, for "Plain C" examples. I have found that many other developers, have also post mixed "plain c" & "c++" examples, (some of them unintentionally).
I'm using some dynamically allocated structures. I have been using "malloc", but I rather use "new" instead. I thought that some new standard & compiler versions of "plain c" allowed "new", but, seems I'm wrong.
Seems that "new" is a "C++" feature, & if I really want to make a only "plain c", I should use "malloc".
The reason I want to stick to "plain C", it's because I'm working in a cross platform non-gui library / tool.
My current platform is "Windowze", my Development Enviroments, are:
(1) CodeBlocks (MinGW)
(2) Bloodshed DevCPP
(3) Borland CBuilder 6
Although, my goal is to migrate it to Linux, too , and maybe other platforms, and other (command-line) compilers.
Quick not Tested Example:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
struct MyData_T
{
int MyInt;
char MyName[512];
char *MyCharPtr;
};
typedef
struct MyData_T *MyData_P;
MyData_P newData(char* AName)
{
MyData_P Result = null;
Result = malloc(sizeof(MyData_T));
strcpy(Result->MyName, AName, strlen(AName));
// do other stuff with fields
return Result;
} // MyData_P newData(...)
int main(...)
{
int ErrorCode = 0;
MyData_P MyDataVar = newData("John Doe");
// do more stuff with "MyDataVar";
free(MyDataVar);
return ErrorCode;
} // int main(...)
Questions
Where I can get a working "plain c only" compiler for x86 (windowze, linux) ?
Should I stick to use "malloc", "calloc", and similar ?
Should I consider to change to "C++" & "new", instead ?
Is it valid to use "new" & "delete" in a "plain c" application ?
Any other suggestion ?
Thanks.
Disclaimer
Note: I already spent several hours trying not to post the same question, in Stackoverflow, but, none of the previous answers seem clear to me.
Remember that C and C++ are actually completely different languages. They share some common syntax, but C is a procedural language and C++ is object oriented, so they are different programming paradigms.
gcc should work just fine as a C compiler. I believe MinGW uses it. It also has flags you can specify to make sure it's using the right version of C (e.g. C99).
If you want to stick with C then you simply won't be able to use new (it's not part of the C language) but there shouldn't be any problems with moving to C++ for a shared library, just so long as you put your Object Oriented hat on when you do.
I'd suggest you just stick with the language you are more comfortable with. The fact that you're using new suggests that will be C++, but it's up to you.
You can use e.g. GCC as a C compiler. To ensure it's compiling as C, use the -x c option. You can also specify a particular version of the C standard, e.g. -std=c99. To ensure you're not using any GCC-specific extensions, you can use the -pedantic flag. I'm sure other compilers have similar options.
malloc and calloc are indeed how you allocate memory in C.
That's up to you.* You say that you want to be cross-platform, but C++ is essentially just as "cross-platform" as C. However, if you're working on embedded platforms (e.g. microcontrollers or DSPs), you may not find C++ compilers for them.
No, new and delete are not supported in C.
* In my opinion, though, you should strongly consider switching to C++ for any application of non-trivial complexity. C++ has far more powerful high-level constructs than C (e.g. smart pointers, containers, templates) that simplify a lot of the tedious work in C. It takes a while to learn how to use them effectively, but in the long run, they will be worth it.
GCC has a C compiler. It's the basic one. You can call it with gcc -std=c90 to make sure it doesn't slip in any Gnu or C++ extensions.
Yes, malloc/calloc are portable and safe for use in C
Only if you have some reason to switch to C++… C is a bit more portable, but not by much, these days.
The most important tip is to save your file with a .c extension and disable compiler extensions. On both Visual C++ and gcc (and thus MinGW) this makes them go into C mode, where C++ additions will be disabled.
You can also force C mode using -std=c90 (or c99, depending on the C standard you want to use; these also disable GNU extensions) in gcc, /Tc in VC++ (and here to disable MS extensions you have to use /Za).
If using visual studio, just make the file .c (though its not strictly a C compiler, it pretends to be, and for the most, is good enough)
*nix world you can use gcc, as its pretty much the standard.
If you want to do C stick to C, if you want to do C++, use C++
so stick with malloc etc.... in C++ you'd use smart pointers.
You don't have to stick with C to create cross platform non-GUI library. You can as well develop that in C++. Since it is hobby, it is OK, but there are such libraries already available.
It seems that starting with C17 (or the technical name ISO/IEC 9899:2018) the new keyword is being supported. To make this work, if you're using Visual Studio Code, in the c_cpp_properties.json file update:
"cStandard": "c17", and
"cppStandard": "c++17"

restrict qualifier compilation error

I am using Code::Blocks 10.05, and mingw. It seems the compiler does not recognized restrict qualifier and return "error: expected ';', ',' or ')' before 'src'". Do I need to pass any compiler option in order to compile it correctly?
int inet_pton4 (const char *restrict src, unsigned char *restrict dst)
p/s: it seems mingw does not support inet_pton4, so i tried to integrate an open-source version into my code.
If your compiler does not support the restrict keyword, just take that keyword out (a).
It's used to indicate to the compiler that you (the developer) promise that the pointers follow certain properties involving aliasing, and this, in turn, allows the compiler to perform certain optimisations that would otherwise not necessarily be safe.
If you leave off that keyword in a compiler that supports it, it prevents those optimisations (slight downside).
If you leave it off for compilers that don't support that keyword, the downside is nil (since they don't support those optimisations anyway) and the upside is considerable, as in "it will compile for you" :-)
(a) You may want to ensure you're compiling in C99 mode first. While it may be true that you're using an older gcc that doesn't understand restrict, it's equally possible that you're not compiling in C99 mode, such as with -std=c99 (gcc docs seem to indicate that restrict has been supported even back to version 3.0).
If, for some reason you cannot activate C99 mode, I think gcc has an extension that allows you to use __restrict.
Since restrict is new in C99, and since, as #paxdiablo points out, omitting the restrict keyword doesn't really hurt anything, you can do this:
#if __STDC_VERSION__ < 199901L
#define restrict /* nothing */
#endif
Put this in a header that's #included by everything in your project (or at least by everything that uses restrict).
This should let your code compile with any C compiler, whether it supports C99 or not. It should even work for a compiler that doesn't define __STDC_VERSION__.
But, since you're using MinGW, which uses gcc, using gcc --std=c99 should also solve the problem (as #paxdiablo also points out).
You can safely do both. (And the #if solution is likely to be useful to others.)

Resources