【问题标题】:Use printf in a GUI application in Code::Blocks在 Code::Blocks 的 GUI 应用程序中使用 printf
【发布时间】:2016-08-18 10:01:56
【问题描述】:

出于调试原因,我希望能够在我的 GUI 应用程序的控制台中使用 printf。我只希望控制台在 Debug 构建目标中可见,而不是在 Release 构建目标中可见。为此,我右键单击工作区中的项目,选择属性...并在构建目标选项卡中选择控制台应用程序类型并选中执行结束时暂停框。完成此操作后,控制台和 GUI 窗口打开正常,但是当我使用 printf 时没有任何反应。如何在带有控制台的 GUI 应用程序中使用 printf

这是我正在使用的代码的相关部分:

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 是一个 int,出于调试原因,我想检查它的值。

这个问题和this不一样,因为在另一个问题中,他们已经知道从IDE运行程序时如何在控制台中写入,而这个问题完全是关于如何在控制台中写入。

【问题讨论】:

标签: c user-interface console codeblocks


【解决方案1】:

SDL 用它自己的入口点覆盖程序入口点。
有关herethereover there 的更多详细信息。

默认情况下,标准输出 (stdout, stdin and stderr) 被重定向到文件,这些文件与它们所保存的流的内容具有相同的名称。
它们应该在您的程序目录中。

1 - 重定向流

要绕过该行为,您必须在 SDL_Init 之后插入以下内容。 如果 add after 不起作用,请尝试将它们添加到 main 的最顶部。

freopen ("CON", "w", stdout);
freopen ("CON", "r", stdin);
freopen ("CON", "w", stderr);

如果还是不行试试。

// 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

了解 CON here

根据我的阅读,“CON”似乎可以替换为 NULL。
物有所值。

freopen(NULL,"w",stdout);
freopen(NULL,"w",stdout);
freopen(NULL,"w",stderr);

freopen 方法的另一个变体。

freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);

更多关于 CONOUT$ 和 CONIN$ here

如果您在使用 GNU/Linux BSD、Solaris、Mac Os 等之前遇到问题。请尝试以下操作。

freopen ("/dev/tty", "w", stdout);
freopen ("/dev/tty", "r", stdin);
freopen ("/dev/tty", "w", stderr);

应用该方法应如下面的代码所示。

/* ... */
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
    /* ... */
}

您可以在SDL faq 上找到该示例。

2 - 更改程序的入口点

您还可以取消定义 SDL 的 main,这样您的 main 将是第一个被调用的。
为此,请在 main 函数之前添加下一条指令。

/*...*/
#ifdef main
    #undef main // Prevent SDL from overriding the program's entry point.
#endif


/***/


int main(int argc, char **argv){
    /*...*/ 
}

/*...*/


#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){
    /*...*/ 
}

关于MINGW32 and MINGW64

3 - 重建 SDL

使用从 SDL 站点下载的预编译 SDLmain.dll 二进制文件,您无法阻止 stdout/stderr 被重定向到文本文件。 您可以做的是使用 NO_STDIO_REDIRECT 编译器标志自己编译 SDLmain,或者根本不使用 SDLmain。

请注意,不使用 SDLmain 会破坏可移植性,不推荐使用。

也就是说,有时将 stdout.txt 和 stderr.txt 写入可执行文件所在的目录会更好。

你可以用一点技巧来做到这一点:

#include "SDL/SDL.h"


#ifdef WIN32
    #include "sdl_winmain.h"
#else
    #include "SDL/SDL_main.h"
#endif

其中 sdl_winmain.h 位于您自己的项目目录中,是 SDL 源包中 src/main/SDL_win32_main.c 的重写副本。这样,您仍然可以移植到其他平台,但不会在 windows 中到处获取 stdout/stderr 文件。

来自SDL faq。如需更多信息,请联系wikifriendly。

3.5 在源中
在源代码(~/SDL2-2.0.4/include/SDL_main.h)中,我发现了以下内容

#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
 */

source code 的在线副本。

如果您没有成功定义 NO_STDIO_REDIRECT,请尝试 SDL_MAIN_HANDLED。
在 SDL-1.2.15 (~/SDL-1.2.15/include/SDL/SDL_main.h) 中找不到它,但是我发现的是

#define main    SDL_main

这似乎与上面的#undef main 方法一致。

4 - 注意
将错误消息发送到 stderr 而不是 stdout 可能会很有趣。为此,请尝试使用 perrorfprintf
像这样:

/*...*/
perror ("Error"); // the string cannot be formatted 
fprintf (stderr,"Error %s", str_err_msg); // the string can be formatted
/*...*/

【讨论】:

  • 我尝试使用 freopen 并没有在 stdout.txt 中写入任何内容,但它也没有在控制台中写入任何内容。我尝试了 CON 和 /dev/tty,但都没有工作。我正在使用 Windows。
  • 据我了解,您的程序必须是控制台应用程序。你这样做了吗?如果这不起作用,我稍后会回复您。
  • 是的,我在我的问题中这么说:“我在工作区中右键单击项目,选择属性...并在构建目标选项卡中选择控制台应用程序类型并选中暂停框执行结束时。”但是,当我创建项目时,我选择了 SDL 项目,这意味着它将自动包含 SDL 库。这应该与在控制台应用程序中手动包含这些库相同。而且我的程序本身不应该是控制台应用,应该是SDL应用,控制台只是用来调试的。
  • 我启动了一段 SDL 代码,但没有任何问题可以打印到控制台。无论如何,我发现了一些东西,所以我会更新我的答案。
  • 还是不行。我创建了一个名为 SDL_InitWitConsole() 的宏,而不是 SDL_Init(),它看起来像这样:#define SDL_InitWithConsole(flags) SDL_Init(flags); FILE *ctt = fopen("CON","w"); freopen("CON","w",stdout); freopen("CON","r",stdin); freopen("CON","w",stderr); fclose(ctt); 和代码 SDL_InitWithFlags(SDL_INIT_VIDEO); printf("hello"); 不打印任何内容。
猜你喜欢
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多