I recently started porting a TON of my C programs to a Windows environment, from my previous Linux development PC. I noticed something a bit off about mingw's Windows GCC implementation.
In Windows, I found a lovely function called getch. It's easy, it's immediate... and it's also non-standard.
I'd like to focus of the "non-standard" part of it. Specifically, I want to know why mingw-gcc allows me to use it, without using anything but the standard libraries.
Assume we have a program that prints "Hello, World!", a NL and CR, and then waits for a key and a return:
#include <stdio.h>
int main(void)
{
char str[14] = "Hello, World!"; //13 characters and a terminator
printf("%s\n\r", str);
scanf("%c");
return 0;
}
Now, let's change a bit of that program to use getch:
#include <stdio.h>
int main(void)
{
char str[14] = "Hello, World!"; //Again, 13 characters and a terminator
printf("%s\n\r", str);
getch(); //See? now it uses getch.
return 0;
}
The interesting part is, Isn't getch a call made by the conio.h library for old DOS/Win32 environments? The compiler doesn't even give a warning. Why does this work?
Here's something I find even a bit more unsettling:
int main(void) //literally NOTHING included
{
getch();
return 0;
}
What on earth? I know for a fact that getch does not exist on Linux environments (natively, anyways). So, where is the compiler getting this call from?
My best guess (please correct me if I am wrong) is that the decision to link whatever has getch is made at link time, not compile time.
In any case, this seems a little odd to me. Why does an implementation of GCC automatically include clearly non-standard capability on Windows?
The compilation step works (though it should produce a warning) because, traditionally, C allows you to call functions that haven't been declared, provided that they return an int which getch() does.
The linking step works because the C runtime library that MinGW uses is a single library, i.e., it provides all the Visual C runtime library functions, including the non-standard ones. MinGW presumably links with it by default because (apart from very rare edge cases) it is always needed, even if all you want is a main() function that does nothing. :-)
It should also be mentioned that the library in question does not officially support third-party use, except by applications built in Visual Studio 6. The more modern runtimes have deprecated getch in favour of the equivalent but standards compliant _getch, but VS6 predates that change.
The compile step will probably 'work' because compilers (at least older versions of compilers — we know that Visual Studio is not up to date with the latest C standards) will assume the return type and the parameters are all int.
The link step will need the appropriate library linked in.
Related
So here's a fun one...
we have a few C libraries which should be platform independent, even though they were developed on linux, because they only rely on the c standard library as defined in ISO/IEC 9899:1999. When we compiled those libraries with MinGW everything seemed to work fine at first, but today we found out that the snprintf() implementation of msvcrt is braindea... sorry, i meant "incompatible" with the definition in the C99 standard.
I would have expected a warning from MinGW, telling me that -std=c99 actually isn't fully supported. Because otherwise, how am i supposed to know?
Is there any alternative c standard library for windows, and most importantly: can MinGW somehow be told to link against it instead of msvcrt?
If not, we would at the very least need a list or something where we can check for other potential portability problems concerning msvcrt and c99.
PS:
I know about Cygwin and MSYS2, but i'd rather have native windows binaries (in part because we also use our libraries in Matlab).
Edit:
Sorry, i should have explained more clearly what exactly my problem with msvcrt's snprintf() is. According to the standard, snprintf() is required to output a '\0' as the last character, if the output doesn't fit. However, msvcrt just doesn't do that, so the resulting string is no longer properly terminated. I have no idea why anyone would choose to implement snprintf() that way, because to me just omitting the '\0' doesn't make any sense at all.
We have also tried the suggested __USE_MINGW_ANSI_STDIO, but i guess that just fixes the missing format specifiers? At least it didn't seem to make a difference for our specific problem.
The standard enforces snprintf to behave like this:
Otherwise, output characters beyond the n-1st are
discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array.
snprintf in msvcrt is indeed not the standard one, but a Microsoft version as explained here:
Is snprintf() ALWAYS null terminating?
The following code gives non-compliant results:
#include <stdio.h>
int main (void)
{
char dst[3];
snprintf(dst, 3, "%c%c%c", 'A', 'B', 'C');
for(size_t i=0; i<3; i++)
{
printf("%.2X ", dst[i]);
}
}
I get output 41 42 43 which is not standard compliant. To get standard C, you have to add this before the stdio.h include:
#define __USE_MINGW_ANSI_STDIO 1
And now you get 41 42 00 which is compliant.
The root of all these program security problems is Microsoft, who have been using non-compliant C libs in their products for the past 20 years.
If you need C99 stdio from MinGW-w64, you can define __USE_MINGW_ANSI_STDIO so that you bypass the msvcrt implementation. It's best to define this through a compiler argument
-D__USE_MINGW_ANSI_STDIO
Alternatively, you could try to use a MinGW-w64 build that is set up to link with the new ucrt, but I don't know of any pre-existing easy-to-use stable builds that are set up that way.
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.
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...
I have a C program where I get function pointers "dynamically" by the function name (ie. I pass the function name as a string and get a pointer to the function). I already do this in Linux using dlopen and dlsym and I suppose it will also work in any other Unix-like with dlfcn.
The problems began when I tried to port this program to Windows using MinGW. When I try to find the name using "GetProcAddress(handle, symbol_name), where "symbol_name" is the name of my callback function and "handle" is a handle to the current executable returned by "GetModuleHandle(NULL)", I get nothing because the MinGW name mangling adds an "_" to my symbol name.
The obvious solution (prefix an "_" to the symbol I want) seems a bit 'dangerous' for portability (may the compiler add two underscores for some of them? I don't know), so, I ask:
There is a better way to prevent the compiler from name-mangling my symbols? (or a subset of them, only the callbacks I need to find dynamically);
Or a way to make GetProcAddress find them even when mangled?
I also tried the option -fno-leading-underscore, but it removed the mangling of all the external symbols too, making the program impossible to link with the stdlib, etc. (also, the warnings on the documentation are a bit scary).
Also, please note that I'm using pure C -- there is no C++ in any part of my code -- and all my code lives in a single ".exe".
TIA
Not sure what your problem is, as I can't reproduce it with the simplest DLL example I can think of:
/* hello_dll.c */
#include <stdio.h>
__declspec(dllexport) void hello ( void )
{
puts ( "Hello, DLL!");
}
/* hello_exe.c */
#include <windows.h>
#include <stdio.h>
int main () {
typedef void (*pfunc)(void);
HANDLE hself;
pfunc hello;
hself = GetModuleHandle(NULL);
hello = (pfunc)GetProcAddress(hdll, "hello");
hello();
return 0;
}
This is the command line using MinGW gcc with no special flags, and it all works:
gcc src\hello_dll.c src\hello_exe.c -o bin\hello.exe
$ bin\hello.exe
Hello, DLL!
$ gcc --version
gcc (GCC) 4.5.0
It doesn't work without the __declspec(dllexport) if you are getting the function from yourself; when creating a DLL with gcc -shared it doesn't appear to be necessary, but appears to be required if exporting a function from an exe.
C doesn't use name mangling. In particular, it doesn't add any type information to the name (unlike C++). But some platforms make a small modification to the name like prefixing the underscore. And unlike C++, it's only platform specific but not compiler specific.
On all the platforms I've seen so far, I've only seen either no modification or the leading underscore.
So I propose you use some ifdefs to derive whether the current platform uses an underscore or not.
(Windows has another small modification for certain Windows API functions for distinguishing the ANSI from the Unicode version. But that's probably not relevant for your case.)
Maybe somebody else can point at some official documentation for the C ABI on different platforms.
So, I'm trying to stuff some default text into a user input using readline, and having trouble getting it to work on OSX 10.5:
// rl_insert_text_ex.c
// gcc -o rl_insert_text_ex rl_insert_text_ex.c -lreadline
#include <stdio.h>
#include <readline/readline.h>
int my_startup_hook(void) {
return rl_insert_text("ponycorns");
}
int main(int argc, char *argv[]) {
char *line;
rl_startup_hook = (Function*) my_startup_hook;
line = readline("What's your favorite mythical animal? ");
if (NULL == line || '\0' == *line) {
printf("Nothing given... :(\n");
}
else {
printf("That's funny, I love %s too!\n", line);
}
return 0;
}
This code doesn't even compile on 10.4 (no definition for _rl_insert_text on 10.4, which is a bit of a bummer), but does compile on 10.5. However, the rl_insert_text()'d text is never shown to screen, nor returned as user input. The callback is being used and rl_insert_text() returns the proper value, (thank you, printf), so I'm not sure what's going on here.
I checked /usr/include/readline/readline.h, and rl_insert_text() is under:
/* supported functions */
which is confusingly under:
/*
* The following is not implemented
*/
So am I SOL, or am I just doing it wrong?
Unfortunately, you may be out of luck, at least with the readline library included in OS X. Due to license compatibility issues, Apple uses libedit, which (apparently) provides incomplete readline emulation. (This library is documented with the name "editline" in the readline.h included with OS X.)
GNU Readline Library (the "one true" readline library) is under GPL, which (being a copyleft license) does not play well with code that is not entirely open-source. If it comes down to (A) open-sourcing all of Xcode, OS X, etc. or (B) using a knock-off of what you're really like to use, Apple (like most companies) is always going to choose B. It's a bummer, but that's life.
Personally, I think this is one reason that GPL'd code is somewhat of a blight on the land, since in the act of "sticking it to the man", it often also withholds the code from the masses who purchase software. The {BSD,MIT,Apache}-style licenses are much more conducive to use in closed-source systems, and still allow commercial entities to contribute back patches, etc. My guess is that libedit hasn't received enough attention to be fixed properly. Community patches would certainly be welcome, although it's so much nicer if we can use code without having to hack on it ourselves... ;-)
BTW, the same thing applies to other GPL projects — as long as {git,mercurial,bazaar} remains under GPL, don't hold your breath for Apple to ship integration for them in Xcode. :-(
UPDATE: The new Xcode 4 offers git support. Huzzah! My understanding is that this is due to the new plugin architecture which isolates GPL'd code from the main Xcode codebase. However, I emphasize that copyleft licenses are still the wrong solution for code that should benefit everyone. Obviously some people don't agree (you're a pal, anonymous downvoter) but the fact is that GPL can restrict freedoms too — usually its different ones than closed-source/proprietary software generally does, but GPL is also quite effective at preventing illegal use of source code... The difference is a feeling of moral superiority.