Awa*_*ain 1 c header codeblocks
我正在尝试调试代码块中的头文件。我尝试了一些选项,例如“运行到光标”并在头文件中放置断点,但它不会在那里停止并通过那里。如何调试其中的 .h 文件?如果您需要任何信息,请发表评论。我会提供信息。
调试器在编译后执行您的程序(并且编译器已被指示将调试信息插入到已编译的程序中)。它允许您在代码中设置的断点处暂停执行,但如果您在程序运行时到达的可执行代码的某行处设置了断点,则它只能在断点处暂停。 如果您在某些不可执行代码的行处设置断点,或者在某些可执行但程序从未到达的行处设置断点,则调试器将永远不会到达该断点。
查看这个玩具 C 程序,并考虑您可以在 Code::Blocks 中设置断点的每个位置A ,..., I :
foo.h
#ifndef FOO_H
#define FOO_H
#define FORTY_TWO 42 /* A */
extern void the_answer_is(void); /*B*/
#endif
Run Code Online (Sandbox Code Playgroud)
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 */
}
Run Code Online (Sandbox Code Playgroud)
主程序
#include "foo.h"
int main(void) /* H */
{
the_answer_is(); /* I */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
A处断点?
这是一个预处理器指令。预处理器在源代码到达编译器之前将其从源代码中删除。所以编译器永远不会看到它。所以调试器对此一无所知。这里没有可执行代码。永远不会到达断点。
B处断点?
这是一个外部函数声明。它向编译器和链接器提供必要的信息。但它不是可执行代码。
extern void the_answer_is(void);不是你的程序可以做的事情。永远不会到达该断点。
C处断点?
这里的故事与A相同,只是预处理器删除了
#include指令并将其替换为 的(预处理的)内容
foo.h。永远不会到达该断点。
D 处断点?
这一行是全局静态初始化。它是在编译时、程序运行之前完成的。没有可执行代码。永远不会到达该断点。
E处断点?
这一行是函数入口点,开始函数定义。它本身不是可执行代码,但它是某些可执行代码的入口点。所以这里可以到达断点。调试器只会稍微“过冲”并停止在函数定义中的第一个可执行行处。如果函数the_answer_is
在执行过程中的某个时刻被调用,您的程序将在此处到达断点。
F处断点?
该行定义并初始化int i. 这里的断点将在与E相同的情况下到达,并且调试器实际上会在E处的断点处停止。
G处断点?
最有趣的一个。该行是对外部库(标准 C 库)中定义的函数的调用。编译器在读取标头时会看到 的
extern声明。
如果您打开并在
的声明处放置断点,则永远不会到达它(与B相同)。但这里我们有一个对 的调用,并且该调用在与E和F相同的情况下达到。printf<stdio.h>stdio.hexternprintfprintf
所以这个断点是可以到达的。但是假设您到达了该位置,然后想要在调试器中单步执行此调用。printf你将无法做到。调试器将直接跳过它。您的程序
已使用调试信息进行编译,但
printf定义的库尚未编译。您根本不编译该库;你只需将它与你的程序链接起来。如果没有有关库的调试信息,也没有访问其源代码,调试器就无法进入它;所以事实并非如此。
您可能会有这样的印象:如果您可以“步入”标头,就像<stdio.h>您会找到在那里声明的库函数的源代码一样,printf并且您可以对其进行调试。你在那里找不到源代码。您会发现的只是外部声明:
extern int printf( const char* format, ... );
Run Code Online (Sandbox Code Playgroud)
对于编译器来说, 的作用<stdio.h>只是告诉它stdio库函数的名称是什么以及如何调用它们。然后它可以告诉您是否调用了尚未声明的函数或以错误的方式调用它。它不需要源代码,printf因为它已经在标准 C 库中编译,您的程序会自动链接到该库。
H处断点?
这是整个程序的入口点,因此总会到达该断点,除非发生灾难性事故。就像E一样 ,调试器将在下一个可执行行处停止。
断点在 I?
这个对 的调用the_answer_is总是会被到达,就像H一样。因为我们现在知道它会被调用,所以我们也知道将会到达the_answer_is断点E、F和G 。
底线:
#include在指令或任何其他预处理器指令处放置断点是没有意义的。编译器永远不会看到它们;调试器对它们一无所知。
一般来说,在 C 中,在头文件中放置断点是没有意义的,因为它们只包含声明和预处理器指令,而不包含可执行代码。(在 C++ 中,情况完全不同。C++ 标头通常包含可执行代码,您可以在其中放置断点。)