Reputation: 8912
I would like to be able to use printf
in the console with my GUI application for debugging reasons. I would only like the console to be visible in the Debug build target, not the Release build target. To do so, I right clicked on the project in the Workspace, selected Properties... and in the Build targets tab I chose Console application in type and checked the box Pause when execution ends. After having done this, the console and the GUI window open fine, but when I use printf
nothing happens. How can I use printf
in a GUI application with a console?
Here is the relevant part of code I'm using:
SDL_Init(SDL_INIT_VIDEO);
putenv("SDL_VIDEO_CENTERED=center");
SDL_WM_SetCaption("Railroad Builder",NULL);
SDL_WM_SetIcon(IMG_Load(strcat_const(parentFolder(exePath),"/icon.png")),NULL);
SDL_SetVideoMode(MAIN_WINDOW_WIDTH,MAIN_WINDOW_HEIGHT,32,SDL_OPENGL);
int running = 1;
while(running){
printf("myVar = %d",myVar);
}
myVar
is a int
that I want to check the value of for debugging reasons.
This question is not the same as this because in the other question, they already know how to write in the console when running the program from the IDE, and this question is about how to write in the console at all.
Upvotes: 1
Views: 2086
Reputation: 729
SDL overrides the program entry point with an entry point of it's own.
More details about that here, there and over there.
By default the standard outputs (stdout, stdin and stderr) are redirected to files, these files possess the same name as the content of the stream they hold.
They should be in your program's directory.
1 - Redireting the stream
To bypass that behaviour you must insert after the SDL_Init the following. If add after does not work try adding them at the very top of the main.
freopen ("CON", "w", stdout);
freopen ("CON", "r", stdin);
freopen ("CON", "w", stderr);
If that still doesn't work try.
// Start : edit
SDL_Init (...)
FILE * ctt = fopen("CON", "w" ); // c
// or
ofstream ctt("CON"); // c++
// End : edit
freopen ("CON", "w", stdout);
freopen ("CON", "r", stdin);
freopen ("CON", "w", stderr);
/* ... */
// Start : edit
fclose (ctt); // c
// or
ctt.close(); // c++
// End : edit
Find out about CON here.
From what i read it seem that "CON" can be replaced with NULL.
(For what it's worth.)
freopen(NULL,"w",stdout);
freopen(NULL,"w",stdout);
freopen(NULL,"w",stderr);
An other variant of the freopen method.
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
More about CONOUT$ and CONIN$ here.
If you are having issues with the previous and using GNU/Linux BSD, Solaris, Mac Os, etc.. try the following.
freopen ("/dev/tty", "w", stdout);
freopen ("/dev/tty", "r", stdin);
freopen ("/dev/tty", "w", stderr);
Applying that method should look as the code below.
/* ... */
int main {
SDL_Init(SDL_INIT_VIDEO);
/* start : redirecting the streams to the console */
FILE * ctt = fopen("CON", "w" ); // Edit
freopen ("CON", "w", stdout);
freopen ("CON", "r", stdin);
freopen ("CON", "w", stderr);
/* end : redirecting the streams to the console */
/*start : your code */
putenv("SDL_VIDEO_CENTERED=center");
SDL_WM_SetCaption("Railroad Builder",NULL);
SDL_WM_SetIcon(IMG_Load(strcat_const(parentFolder(exePath),
"/icon.png")),NULL);
SDL_SetVideoMode(MAIN_WINDOW_WIDTH,MAIN_WINDOW_HEIGHT,32,
SDL_OPENGL);
int running = 1;
while(running){
printf("myVar = %d",myVar);
}
/* end : your code */
/* ... */
fclose (ctt); // Edit
/* ... */
}
You can find that exemple on the SDL faq.
2 - Changing the program's entry point
You can also undefine SDL's main so your main will be the first to be called.
To do so add the the next instructions before the main function.
/*...*/
#ifdef main
#undef main // Prevent SDL from overriding the program's entry point.
#endif
/***/
int main(int argc, char **argv){
/*...*/
}
or
/*...*/
#ifdef __MINGW32__ // It can be __MINGW64__. Chose according to your architecture.
#undef main // Prevent SDL from overriding the program's entry point.
#endif
//or
#if defined(__MINGW32__) || defined(__MINGW64__)
#undef main // Prevent SDL from overriding the program's entry point.
#endif
/*...*/
int main(int argc, char **argv){
/*...*/
}
About MINGW32 and MINGW64
3 - Rebuilding SDL
With the precompiled SDLmain.dll binary downloaded from the SDL site you cannot prevent the stdout/stderr from being redirected to textfiles. What you can do is compile SDLmain yourself with the NO_STDIO_REDIRECT compiler flag or alternatively not use SDLmain at all.
Note that not using SDLmain will break portability and is not recommended.
That said sometimes it's nicer to just have the stdout.txt and stderr.txt written to the directory where the executable is.
You can do this with a little trickery:
#include "SDL/SDL.h"
#ifdef WIN32
#include "sdl_winmain.h"
#else
#include "SDL/SDL_main.h"
#endif
Where sdl_winmain.h is in your own project directory and is a rewritten copy of src/main/SDL_win32_main.c from the SDL source package. This way you will still have portability for other platforms but not get stdout/stderr files all over the place in windows.
That's from the SDL faq. For further information get wiki friendly.
3.5 In the source
In the source code (~/SDL2-2.0.4/include/SDL_main.h) I've found the following
#ifndef SDL_MAIN_HANDLED
#if defined(__WIN32__)
/* On Windows SDL provides WinMain(), which parses the command line and passes
the arguments to your main function.
If you provide your own WinMain(), you may define SDL_MAIN_HANDLED
*/
A online copy of the source code.
If you have no success with defining NO_STDIO_REDIRECT try SDL_MAIN_HANDLED.
It was nowhere to found in SDL-1.2.15 (~/SDL-1.2.15/include/SDL/SDL_main.h) however, what I did find is
#define main SDL_main
That seem to be in accordance with the #undef main methode from above.
4 - Note
It might be interesting to send the error message to stderr instead of stdout. To do so try using perror or fprintf.
Like so :
/*...*/
perror ("Error"); // the string cannot be formatted
fprintf (stderr,"Error %s", str_err_msg); // the string can be formatted
/*...*/
Upvotes: 2