在代码块中调试头文件
Debugging header files in codeblocks
我正在尝试调试代码块中的头文件。我已经尝试了一些选项,例如 "run to cursor" 并通过在头文件中放置断点,但它不会停在那里并通过那里。
如何调试其中的 .h 文件?
如果您需要任何信息,请发表评论。我会提供信息。
调试器会在你的程序被编译后执行你的程序(而且编译器已经
指示将 调试信息 插入已编译的程序)。它可以让你暂停
在您在代码中设置的断点处执行,但它只能在断点处暂停,如果
您已在程序运行时到达的某行可执行代码处设置断点。
如果您在某行不是可执行代码或在某行 是 可执行代码处设置断点
但是程序永远不会到达,那么调试器永远不会到达那个断点。
看看这个玩具 C 程序并考虑每个地方 A,...,I 您可以在其中设置
Code::Blocks 中的断点:
foo.h
#ifndef FOO_H
#define FOO_H
#define FORTY_TWO 42 /* A */
extern void the_answer_is(void); /*B*/
#endif
foo.c
#include "foo.h" /* C */
#include <stdio.h>
static int forty_two = FORTY_TWO; /* D */
void the_answer_is(void) /* E */
{
int i = forty_two; /* F */
printf("The answer is...%d\n",i); /* G */
}
main.c
#include "foo.h"
int main(void) /* H */
{
the_answer_is(); /* I */
return 0;
}
断点在A?
这是一个预处理器指令。预处理器将其从源中删除
代码在到达编译器之前。所以编译器永远不会看到它。所以
调试器对此一无所知。这里没有可执行代码。一个断点
永远达不到。
B处断点?
这是一个外部函数声明。它提供必要的信息给
编译器和 linker。但它不是可执行代码。
extern void the_answer_is(void);
不是您的程序可以 做的事情 。
永远不会达到此断点。
断点在C?
这里的故事与 A 相同,除了预处理器删除了
#include
指令并将其替换为(预处理的)内容
foo.h
。永远不会达到此断点。
断点在D?
这一行是全局静态初始化。它是在编译时完成的,
在你的程序运行之前。没有可执行代码。永远不会达到此断点。
断点在 E?
这一行是一个函数入口点,开始一个函数定义。
它本身不是可执行代码,但它是某些程序的入口点
可执行代码。所以可以到达这里的断点。调试器将
只是 "overshoot" 一点,然后停在第一个可执行行
函数定义。如果函数the_answer_is
,您的程序将在此处到达断点
在执行的某个时刻被调用。
断点在F?
这一行定义并初始化int i
。这里的断点将是
在与 E 相同的情况下达到,它是调试器所在的位置
实际上会在 E.
的断点处停止
断点在G?
最有趣的一个。这一行是对一个函数的调用
在外部库(标准 C 库)中定义。编译器将看到
extern
printf
读取 header <stdio.h>
时的声明
如果您打开了 stdio.h
并在 extern
处放置了一个断点
printf
的声明,它永远不会到达(与 B 相同)。但
这里我们有一个 调用 到 printf
,并且该调用可以在
与 E 和 F.
相同的情况
所以可以到达这个断点。但是假设你到达了它并且你
然后想在调试器中进入这个对[=20=]的调用。你
将无法。调试器将跳过它。 你的程序
已经编译了调试信息,但是其中的库
printf
定义了还没有。您根本不编译该库;你刚才
link 它与您的程序。没有关于库的调试信息,
并访问它的源代码,调试器不能进入它;所以
没有。
您可能认为如果您可以 "step into"
a header like <stdio.h>
你会找到
在那里声明的库函数,比如说 printf
,你可以
调试它。你不会在那里找到源代码。你会发现的是
外部声明:
extern int printf( const char* format, ... );
<stdio.h>
对你的编译器的作用只是告诉它名字是什么
stdio
库函数的名称及其调用方式。然后
它可以告诉你是否调用了一个尚未声明的函数或调用它
以错误的方式。它不需要 printf
的源代码,因为它已经编译在
标准 C 库,您的程序会自动 link 编辑。
断点在H?
这是你整个程序的入口点,所以这个断点
总是,除非发生灾难性事故。就如同
E,调试器将在下一个可执行行停止。
断点在 I?
这个对the_answer_is
的调用总会到达,就像H一样。
因为我们现在知道 the_answer_is
得到所有,我们也知道
断点 E,F 和 G 将 达到了。
底线:
在#include
指令处设置断点是没有意义的
或任何其他预处理器指令。编译器永远看不到它们;
调试器对它们一无所知。
一般来说,在C中,把断点放在header里面是没有意义的
文件,因为它们只包含声明和预处理器
指令,而不是可执行代码。 (在 C++ 中,情况完全不同。
C++ headers 通常包含可执行代码,您可以放置断点
在他们里面。)
我正在尝试调试代码块中的头文件。我已经尝试了一些选项,例如 "run to cursor" 并通过在头文件中放置断点,但它不会停在那里并通过那里。 如何调试其中的 .h 文件? 如果您需要任何信息,请发表评论。我会提供信息。
调试器会在你的程序被编译后执行你的程序(而且编译器已经 指示将 调试信息 插入已编译的程序)。它可以让你暂停 在您在代码中设置的断点处执行,但它只能在断点处暂停,如果 您已在程序运行时到达的某行可执行代码处设置断点。 如果您在某行不是可执行代码或在某行 是 可执行代码处设置断点 但是程序永远不会到达,那么调试器永远不会到达那个断点。
看看这个玩具 C 程序并考虑每个地方 A,...,I 您可以在其中设置 Code::Blocks 中的断点:
foo.h
#ifndef FOO_H
#define FOO_H
#define FORTY_TWO 42 /* A */
extern void the_answer_is(void); /*B*/
#endif
foo.c
#include "foo.h" /* C */
#include <stdio.h>
static int forty_two = FORTY_TWO; /* D */
void the_answer_is(void) /* E */
{
int i = forty_two; /* F */
printf("The answer is...%d\n",i); /* G */
}
main.c
#include "foo.h"
int main(void) /* H */
{
the_answer_is(); /* I */
return 0;
}
断点在A?
这是一个预处理器指令。预处理器将其从源中删除 代码在到达编译器之前。所以编译器永远不会看到它。所以 调试器对此一无所知。这里没有可执行代码。一个断点 永远达不到。
B处断点?
这是一个外部函数声明。它提供必要的信息给
编译器和 linker。但它不是可执行代码。
extern void the_answer_is(void);
不是您的程序可以 做的事情 。
永远不会达到此断点。
断点在C?
这里的故事与 A 相同,除了预处理器删除了
#include
指令并将其替换为(预处理的)内容
foo.h
。永远不会达到此断点。
断点在D?
这一行是全局静态初始化。它是在编译时完成的, 在你的程序运行之前。没有可执行代码。永远不会达到此断点。
断点在 E?
这一行是一个函数入口点,开始一个函数定义。
它本身不是可执行代码,但它是某些程序的入口点
可执行代码。所以可以到达这里的断点。调试器将
只是 "overshoot" 一点,然后停在第一个可执行行
函数定义。如果函数the_answer_is
,您的程序将在此处到达断点
在执行的某个时刻被调用。
断点在F?
这一行定义并初始化int i
。这里的断点将是
在与 E 相同的情况下达到,它是调试器所在的位置
实际上会在 E.
断点在G?
最有趣的一个。这一行是对一个函数的调用
在外部库(标准 C 库)中定义。编译器将看到
extern
printf
读取 header <stdio.h>
时的声明
如果您打开了 stdio.h
并在 extern
处放置了一个断点
printf
的声明,它永远不会到达(与 B 相同)。但
这里我们有一个 调用 到 printf
,并且该调用可以在
与 E 和 F.
所以可以到达这个断点。但是假设你到达了它并且你
然后想在调试器中进入这个对[=20=]的调用。你
将无法。调试器将跳过它。 你的程序
已经编译了调试信息,但是其中的库
printf
定义了还没有。您根本不编译该库;你刚才
link 它与您的程序。没有关于库的调试信息,
并访问它的源代码,调试器不能进入它;所以
没有。
您可能认为如果您可以 "step into"
a header like <stdio.h>
你会找到
在那里声明的库函数,比如说 printf
,你可以
调试它。你不会在那里找到源代码。你会发现的是
外部声明:
extern int printf( const char* format, ... );
<stdio.h>
对你的编译器的作用只是告诉它名字是什么
stdio
库函数的名称及其调用方式。然后
它可以告诉你是否调用了一个尚未声明的函数或调用它
以错误的方式。它不需要 printf
的源代码,因为它已经编译在
标准 C 库,您的程序会自动 link 编辑。
断点在H?
这是你整个程序的入口点,所以这个断点 总是,除非发生灾难性事故。就如同 E,调试器将在下一个可执行行停止。
断点在 I?
这个对the_answer_is
的调用总会到达,就像H一样。
因为我们现在知道 the_answer_is
得到所有,我们也知道
断点 E,F 和 G 将 达到了。
底线:
在
#include
指令处设置断点是没有意义的 或任何其他预处理器指令。编译器永远看不到它们; 调试器对它们一无所知。一般来说,在C中,把断点放在header里面是没有意义的 文件,因为它们只包含声明和预处理器 指令,而不是可执行代码。 (在 C++ 中,情况完全不同。 C++ headers 通常包含可执行代码,您可以放置断点 在他们里面。)