在 Eclipse 中进行 C 编程时的奇怪行为
Weird behavior while doing C programming in eclipse
好久好久没碰C了。我的第一语言是 C。但后来我们学习了 C++、Java 和 C#(在大学时代)。现在我的大部分工作涉及 Java 和 groovy。突然间我不得不再次做C。我不熟悉行业如何使用 C,因为我从来没有在项目中用 C 做事。
我从 eclipse CDT 开始,在 Windows 10 上使用 MinGW。我的新程序发展很快。我缺乏经验并没有透露给我。当我 运行 时,我的程序曾经崩溃,显示 Windows 对话框说 "MyProgram.exe has stopped working"。现在我不知道出了什么问题。编译很干净,没有错误,但只有一个警告。现在从 Java 世界开始,我觉得警告并不是那么致命。所以我只是忽略了它(那是我缺乏 C 经验)。并继续调试找到了原因。意识到警告确实是关于原因的。因在调试中浪费时间而遭受精神挫败。
所以这是我原始代码中的代码复制问题:
1 #include "stdio.h"
2 #include "limits.h"
3
4 typedef struct TempStruct TempStruct;
5
6 struct TempStruct
7 {
8 int a;
9 TempStruct *next;
10 };
11
12 int function1(TempStruct *param)
13 {
14 return param == NULL;
15 }
16
17 int function2(TempStruct **param)
18 {
19 if(function1(param))
20 {
21 return INT_MIN;
22 }
23 *param = (*param)->next;
24 return 0;
25 }
26
27 int main()
28 {
29 TempStruct *tempStructObj = NULL;
30 function2(&tempStructObj);
31 printf("Does not reach here!!!");
32 return 0;
33 }
我的C菜鸟眼睛没看出有什么不对的地方。很好,我知道如何进行调试。我在调试中得到以下信息:
在 main()
中完成:*tempStructObj = NULL
。所以,我期待 function1()
到 return 1,从第 21 行开始 function2()
returning。
问题是 function1()
需要 TempStruct*
。但是在第19行,我通过了**param
。所以在 function1()
里面,param
不是 NULL
。所以它 returned false
(0
我猜)。所以 function2()
没有从第 21 行开始 return。它执行了 (*param)->next
,因此程序崩溃了。
我的问题:
- Q1. 不应该将此类问题报告为错误而不是警告?是否有任何设置可以将此类潜在的致命警告报告为错误?
- Q2. eclipse 是否记录了应用突然崩溃的原因?因此,我可以简单地参考可能指定导致崩溃的行号的报告,而不是逐行调试
- Q3.处理此类错误的行业标准方法是什么?当然有人会说不要犯错误。但我问的是为避免此类错误或自动检测此类错误而采取的预防措施。像上面一样,我询问了有关设置,以使 eclipse 将问题报告为致命问题或使崩溃生成报告,以便可以快速修复问题,而不是花费数小时的调试时间。您是否使用更好的(并且可能涉及更小的学习曲线)替代 (eclipse CDT + MinGW + Windows) 将提供更强大的调试,以便我可以避免此类错误。
- Q4. 上图第1点,
Error: Multiple errors reported...
是什么。这种情况偶尔会发生,但并非总是如此,比如每 5 个调试会话一次。这种临时行为背后的原因是什么?
Q5. 在上图的第 3 点中,[=13] 中 param
的 (0x62ff2c
) 值是多少=]?如果我将 function1()
的签名正确保留为 int function1(TempStruct **param)
,并将内部引用正确更改为 *param
,则 *param
正确地 0x0
(即 NULL
):
编辑
当你
TempStruct *tempStructObj = NULL;
function2(&tempStructObj);
您正在向 function2
发送变量 tempStructObj
(0x62ff2c) 的地址。当做
if(function1(param)){
return INT_MIN;
}
您正在发送相同的地址 (0x62ff2c)。因此,param == NULL
是 false
。
问题 5:如果按照您的建议使用正确的签名,那么您会检查 tempStructObj
指向的值,这是您想要的,并且一切正常。
你得到的关于无法访问内存 0x4 的错误是由于你的结构和错误的空检查。 (*param)->next
预期在具有 int
和另一个指针的内存区域上工作。但是,*param
指向地址 0x0,因此 int 位于地址 0x0,而 next
指针位于地址 0x4,因此出现错误。
Q1。不,它们是警告,因为它们是合法的 C 代码。 可能您需要这样的代码。您可以在 gcc 上使用 -Werror
来对错误发出警告。还要添加一些其他标志以打开更多警告,例如 -Wall -Wpedantic -Wextra -Wshadow -Wconversion -Wno-sign-compare
等。这会更接近您在使用 Java 时可能习惯的内容;-)
Q2。至少在 Linux 上你有核心转储,iirc Windows 是小型转储。这些可以与相应的可执行文件一起加载到调试器中。然后你可以访问回溯、值等。
Q3.
Like above I asked about settings to make eclipse report the issue as fatal one or making crashes to generate report so that stuff can be fixed quickly instead of hours long debuggins.
自己登录。也可以有宏来缓解这个问题。
Do you use any better (and possibly involving smaller learning curve) alternative to (eclipse CDT + MinGW + Windows) that will provide more powerful debugging so that I can avoid such errors.
IDE 与 C imho 无关。将 Linux 与本机 GCC 结合使用,MinGW 很不错,但它可能令人生畏(我的经验)。
当然 MS VSC++ 也可以编译 C,但它只是为了 C++ 兼容,因此并不特定于某一标准。
Q4。好吧,列出了多个错误。如果难以重现,则可能是您的设置有问题,这正是我在 Windows.
上使用 MinGW 的经历
Q5。它是地址——你有一个指向指针的指针,所以第一个 ("outer") 指针就是那个地址,指向另一个指针 NULL
。
或者更详细地说:
tempStructObj
是指向 NULL
的指针(即 int_ptr
保存值 0x0
。
你传给function2
另一个int_ptr
里面保存了自动变量int_ptr tempStructObj
的半随机value/address
IE。你有这样的:
地址&tempStructObj
:tempStructObj
在内存中。
当您随后调用 function1
时,您将传递此 (not-NULL
) 指针的值。当然,这种比较总是错误的。
你需要比较
*param
与 NULL
.
更多:
如果您使用 GCC(在 Linux 上)编译并使用非常冗长的标志,您会得到:
gcc -std=c99 -Wall -Wpedantic -Wextra -Wshadow -Wconversion -Wno-sign-compare -o main main.c
main.c: In function ‘function2’:
main.c:19:18: warning: passing argument 1 of ‘function1’ from incompatible pointer type [-Wincompatible-pointer-types]
if(function1(param))
^
main.c:12:5: note: expected ‘TempStruct * {aka struct TempStruct *}’ but argument is of type ‘TempStruct ** {aka struct TempStruct **}’
int function1(TempStruct *param)
^
这正是你遇到的问题^^
另外,我会完全删除 function1
,这是完全没有必要的,只会混淆代码。此外,我会为 struct
和 typedef
使用不同的名称,并在后者后面附加一个 _t
。另外,我会将它移到一段较短的代码中。
附带说明:在 printf()
-call.
中添加一个 \n
编辑代码:
#include <stdio.h>
#include <limits.h>
typedef struct TempStruct_s {
int a;
struct TempStruct_s *next;
} TempStruct_t;
int function(TempStruct_t **param)
{
if(!*param) {
return INT_MIN;
}
*param = (*param)->next;
return 0;
}
int main()
{
TempStruct_t *tempStructObj = NULL;
function(&tempStructObj);
printf("Does not reach here!!!\n");
return 0;
}
好久好久没碰C了。我的第一语言是 C。但后来我们学习了 C++、Java 和 C#(在大学时代)。现在我的大部分工作涉及 Java 和 groovy。突然间我不得不再次做C。我不熟悉行业如何使用 C,因为我从来没有在项目中用 C 做事。
我从 eclipse CDT 开始,在 Windows 10 上使用 MinGW。我的新程序发展很快。我缺乏经验并没有透露给我。当我 运行 时,我的程序曾经崩溃,显示 Windows 对话框说 "MyProgram.exe has stopped working"。现在我不知道出了什么问题。编译很干净,没有错误,但只有一个警告。现在从 Java 世界开始,我觉得警告并不是那么致命。所以我只是忽略了它(那是我缺乏 C 经验)。并继续调试找到了原因。意识到警告确实是关于原因的。因在调试中浪费时间而遭受精神挫败。
所以这是我原始代码中的代码复制问题:
1 #include "stdio.h"
2 #include "limits.h"
3
4 typedef struct TempStruct TempStruct;
5
6 struct TempStruct
7 {
8 int a;
9 TempStruct *next;
10 };
11
12 int function1(TempStruct *param)
13 {
14 return param == NULL;
15 }
16
17 int function2(TempStruct **param)
18 {
19 if(function1(param))
20 {
21 return INT_MIN;
22 }
23 *param = (*param)->next;
24 return 0;
25 }
26
27 int main()
28 {
29 TempStruct *tempStructObj = NULL;
30 function2(&tempStructObj);
31 printf("Does not reach here!!!");
32 return 0;
33 }
我的C菜鸟眼睛没看出有什么不对的地方。很好,我知道如何进行调试。我在调试中得到以下信息:
在 main()
中完成:*tempStructObj = NULL
。所以,我期待 function1()
到 return 1,从第 21 行开始 function2()
returning。
问题是 function1()
需要 TempStruct*
。但是在第19行,我通过了**param
。所以在 function1()
里面,param
不是 NULL
。所以它 returned false
(0
我猜)。所以 function2()
没有从第 21 行开始 return。它执行了 (*param)->next
,因此程序崩溃了。
我的问题:
- Q1. 不应该将此类问题报告为错误而不是警告?是否有任何设置可以将此类潜在的致命警告报告为错误?
- Q2. eclipse 是否记录了应用突然崩溃的原因?因此,我可以简单地参考可能指定导致崩溃的行号的报告,而不是逐行调试
- Q3.处理此类错误的行业标准方法是什么?当然有人会说不要犯错误。但我问的是为避免此类错误或自动检测此类错误而采取的预防措施。像上面一样,我询问了有关设置,以使 eclipse 将问题报告为致命问题或使崩溃生成报告,以便可以快速修复问题,而不是花费数小时的调试时间。您是否使用更好的(并且可能涉及更小的学习曲线)替代 (eclipse CDT + MinGW + Windows) 将提供更强大的调试,以便我可以避免此类错误。
- Q4. 上图第1点,
Error: Multiple errors reported...
是什么。这种情况偶尔会发生,但并非总是如此,比如每 5 个调试会话一次。这种临时行为背后的原因是什么? Q5. 在上图的第 3 点中,[=13] 中
param
的 (0x62ff2c
) 值是多少=]?如果我将function1()
的签名正确保留为int function1(TempStruct **param)
,并将内部引用正确更改为*param
,则*param
正确地0x0
(即NULL
):编辑
当你
TempStruct *tempStructObj = NULL;
function2(&tempStructObj);
您正在向 function2
发送变量 tempStructObj
(0x62ff2c) 的地址。当做
if(function1(param)){
return INT_MIN;
}
您正在发送相同的地址 (0x62ff2c)。因此,param == NULL
是 false
。
问题 5:如果按照您的建议使用正确的签名,那么您会检查 tempStructObj
指向的值,这是您想要的,并且一切正常。
你得到的关于无法访问内存 0x4 的错误是由于你的结构和错误的空检查。 (*param)->next
预期在具有 int
和另一个指针的内存区域上工作。但是,*param
指向地址 0x0,因此 int 位于地址 0x0,而 next
指针位于地址 0x4,因此出现错误。
Q1。不,它们是警告,因为它们是合法的 C 代码。 可能您需要这样的代码。您可以在 gcc 上使用 -Werror
来对错误发出警告。还要添加一些其他标志以打开更多警告,例如 -Wall -Wpedantic -Wextra -Wshadow -Wconversion -Wno-sign-compare
等。这会更接近您在使用 Java 时可能习惯的内容;-)
Q2。至少在 Linux 上你有核心转储,iirc Windows 是小型转储。这些可以与相应的可执行文件一起加载到调试器中。然后你可以访问回溯、值等。
Q3.
Like above I asked about settings to make eclipse report the issue as fatal one or making crashes to generate report so that stuff can be fixed quickly instead of hours long debuggins.
自己登录。也可以有宏来缓解这个问题。
Do you use any better (and possibly involving smaller learning curve) alternative to (eclipse CDT + MinGW + Windows) that will provide more powerful debugging so that I can avoid such errors.
IDE 与 C imho 无关。将 Linux 与本机 GCC 结合使用,MinGW 很不错,但它可能令人生畏(我的经验)。 当然 MS VSC++ 也可以编译 C,但它只是为了 C++ 兼容,因此并不特定于某一标准。
Q4。好吧,列出了多个错误。如果难以重现,则可能是您的设置有问题,这正是我在 Windows.
上使用 MinGW 的经历Q5。它是地址——你有一个指向指针的指针,所以第一个 ("outer") 指针就是那个地址,指向另一个指针 NULL
。
或者更详细地说:
tempStructObj
是指向 NULL
的指针(即 int_ptr
保存值 0x0
。
你传给function2
另一个int_ptr
里面保存了自动变量int_ptr tempStructObj
的半随机value/address
IE。你有这样的:
地址&tempStructObj
:tempStructObj
在内存中。
当您随后调用 function1
时,您将传递此 (not-NULL
) 指针的值。当然,这种比较总是错误的。
你需要比较
*param
与 NULL
.
更多: 如果您使用 GCC(在 Linux 上)编译并使用非常冗长的标志,您会得到:
gcc -std=c99 -Wall -Wpedantic -Wextra -Wshadow -Wconversion -Wno-sign-compare -o main main.c
main.c: In function ‘function2’:
main.c:19:18: warning: passing argument 1 of ‘function1’ from incompatible pointer type [-Wincompatible-pointer-types]
if(function1(param))
^
main.c:12:5: note: expected ‘TempStruct * {aka struct TempStruct *}’ but argument is of type ‘TempStruct ** {aka struct TempStruct **}’
int function1(TempStruct *param)
^
这正是你遇到的问题^^
另外,我会完全删除 function1
,这是完全没有必要的,只会混淆代码。此外,我会为 struct
和 typedef
使用不同的名称,并在后者后面附加一个 _t
。另外,我会将它移到一段较短的代码中。
附带说明:在 printf()
-call.
\n
编辑代码:
#include <stdio.h>
#include <limits.h>
typedef struct TempStruct_s {
int a;
struct TempStruct_s *next;
} TempStruct_t;
int function(TempStruct_t **param)
{
if(!*param) {
return INT_MIN;
}
*param = (*param)->next;
return 0;
}
int main()
{
TempStruct_t *tempStructObj = NULL;
function(&tempStructObj);
printf("Does not reach here!!!\n");
return 0;
}