1

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?

Mason Watmough
  • 495
  • 6
  • 19
  • 1
    Did you know that you can call functions without declaring them in C? – user253751 Feb 03 '16 at 04:26
  • @immibis I do. But what I'm asking is how and why GCC of all compilers interprets that `getch` call and knows what to do with it without any guidance whatsoever,. – Mason Watmough Feb 03 '16 at 04:29
  • 3
    `conio.h` is a header, not a library. It declares functions (and defines types, etc). You're not compiling with any warning options worth mentioning because if you were, the compiler would complain that you've not declared `getch()` before you used it (and it would complain about the missing argument in the `scanf("%c")` call in the first program). The MinGW compiler links with the local C library — it is a Minimal GNU environment for Windows, so it links with the MS C runtime library (libraries) which include `getch()`. If you compile in C99 or C11 mode, you have to declare functions first. – Jonathan Leffler Feb 03 '16 at 05:24
  • Also, the line ending sequence on Windows is `\r\n` and not `\n\r`. Further complicating things is that text mode input operations will translate the native `\r\n` to just `\n` and the output operations will translate `\n` to `\r\n`. This transform does not occur with binary mode I/O. – Jonathan Leffler Feb 03 '16 at 05:25
  • @MasonWatmough Same way it knows how to call `printf` when you call `printf`. – user253751 Feb 03 '16 at 08:08
  • @immibis That's not what I mean. `printf` is included and linked because it's part of the standard library. `getch` is not. – Mason Watmough Feb 04 '16 at 02:32
  • @JonathanLeffler That makes more sense. I was not aware that `mingw-gcc` was treating Windows C and its parts as standard, because according to Windows, I suppose it would be. – Mason Watmough Feb 04 '16 at 02:35
  • 1
    @MasonWatmough `getch` is part of the standard library on Windows. – user253751 Feb 04 '16 at 02:39
  • in the 'original' code, the `scanf("%c");` raises a warning because no parameter containing address of a char for the format specifier '%c' to input to. This needs correction – user3629249 Feb 05 '16 at 03:05
  • in the 'windows' version of the posted code, the compiler will raise the warning: "warning: implicit declaration of function 'getch' [-Wimplicit-function-declaration]". Save your self lots of aggravation and use `getchar()`. – user3629249 Feb 05 '16 at 03:08
  • Try invoking the compiler in standard mode. It defaults to "useful mode" . E.g. use switches `-std=c11 -pedantic`. You should get messages from the compiler for your last example, even in the default mode. – M.M Feb 05 '16 at 03:22
  • Not *directly* relevant, but you should note that MinGW is using the C runtime shipped with Windows, which is designed only for two uses: use by Windows itself, and use by programs compiled in Visual Studio 6, circa 1998. So as standard libraries go, it isn't very. :-) – Harry Johnston Feb 06 '16 at 00:38

2 Answers2

1

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.

Community
  • 1
  • 1
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
-1

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • 1
    In the absence of a prototype, the compiler does _not_ assume that the parameters are all `int`; it applies the default promotions (shorter than `int` to `int`; `float` to `double`) and makes no assumptions about the number of arguments or the types (except that it knows the function is not a variadic function with `...` at the end of its argument list — such functions must always be properly declared, even in C89/C90). – Jonathan Leffler Feb 05 '16 at 03:25
  • 'modern' compilers don't make the assumption, however, Visual Studio is way behind and still makes the assumption. Also, the discussion is not about a variadic function. – user3629249 Feb 05 '16 at 03:35
  • Ancient compilers don't make the assumption that the parameters are all `int` either. To think otherwise is a nonsense — you'd never be able to pass a `double` or a pointer to any function if what you said were true. Granted, the discussion is not about variadic functions; they are marginally relevant since the requirements on using them is different from the requirements on using non-variadic (fixed argument) functions. – Jonathan Leffler Feb 05 '16 at 03:39
  • Note that the OP isn't using VS anyway. – Harry Johnston Feb 06 '16 at 00:30