当链接源中的函数定义与标头中的函数原型不同时,gcc 不会发出警告
我的代码的一部分出现了问题,经过一些迭代后,它似乎将 NaN 读取为结构体的 double 值。我想我发现了错误,但我仍然想知道为什么 gcc(带有 busybox 的嵌入式 Linux 上的版本 3.2.3)没有警告我。以下是代码的重要部分:
一个 c 文件及其用于通过 USB 获取数据的函数的头文件:
// usb_control.h
typedef struct{
double mean;
short *values;
} DATA_POINTS;
typedef struct{
int size;
DATA_POINTS *channel1;
//....7 more channels
} DATA_STRUCT;
DATA_STRUCT *create_data_struct(int N); // N values per channel
int free_data_struct(DATA_STRUCT *data);
int aqcu_data(DATA_STRUCT *data, int N);
一个带有辅助函数(数学、位移位等...)的 c 和头文件:
// helper.h
int mean(DATA_STRUCT *data);
// helper.c (this is where the error is obviously)
double mean(DATA_STRUCT *data)
{
// sum in for loop
data->channel1->mean = sum/data->N;
// ...7 more channels
// a printf here displayed the mean values corretly
}
主文件
// main.c
#include "helper.h"
#include "usb_control.h"
// Allocate space for data struct
DATA_STRUCT *data = create_data_struct(N);
// get data for different delays
for (delay = 0; delay < 500; delay += pw){
acqu_data(data, N);
mean(data);
printf("%.2f",data->channel1->mean); // done for all 8 channels
// printf of the mean values first is correct. Than after 5 iterations
// it is always NaN for channel1. The other channels are displayed correctly;
}
没有段错误,也没有任何其他错误行为,只是主文件中通道 1 的 NaN。
发现错误后,这并不容易,当然也很容易修复。 mean(){}
的返回类型定义错误。正如原型定义的那样,它必须是 int Mean()
,而不是 doublemean()
。当所有函数都放入一个文件中时,gcc 警告我函数 mean()
被重新定义。但是当我单独编译每个 c 文件并随后链接它们时,gcc 似乎错过了这一点。
所以我的问题是。为什么我没有收到任何警告,甚至没有收到 gcc -Wall 的警告?或者是否还隐藏了另一个错误,但现在不会造成问题?
问候, 基督教
I had a problem with a part of my code, which after some iterations seemed to read NaN as value of a double
of a struct. I think I found the error, but am still wondering why gcc (version 3.2.3 on a embedded Linux with busybox) did not warn me. Here are the important parts of the code:
A c file and its header for functions to acquire data over USB:
// usb_control.h
typedef struct{
double mean;
short *values;
} DATA_POINTS;
typedef struct{
int size;
DATA_POINTS *channel1;
//....7 more channels
} DATA_STRUCT;
DATA_STRUCT *create_data_struct(int N); // N values per channel
int free_data_struct(DATA_STRUCT *data);
int aqcu_data(DATA_STRUCT *data, int N);
A c and header file with helper function (math, bitshift,etc...):
// helper.h
int mean(DATA_STRUCT *data);
// helper.c (this is where the error is obviously)
double mean(DATA_STRUCT *data)
{
// sum in for loop
data->channel1->mean = sum/data->N;
// ...7 more channels
// a printf here displayed the mean values corretly
}
The main file
// main.c
#include "helper.h"
#include "usb_control.h"
// Allocate space for data struct
DATA_STRUCT *data = create_data_struct(N);
// get data for different delays
for (delay = 0; delay < 500; delay += pw){
acqu_data(data, N);
mean(data);
printf("%.2f",data->channel1->mean); // done for all 8 channels
// printf of the mean values first is correct. Than after 5 iterations
// it is always NaN for channel1. The other channels are displayed correctly;
}
There were no segfaults nor any other missbehavior, just the NaN for channel1 in the main file.
After finding the error, which was not easy, it was of course east to fix. The return type of mean(){}
was wrong in the definition. Instead of double mean()
it has to be int mean()
as the prototype defines. When all the functions are put into one file, gcc warns me that there is a redefinition of the function mean()
. But as I compile each c file seperately and link them afterwards gcc seems to miss that.
So my questions would be. Why didn't I get any warnings, even non with gcc -Wall? Or is there still another error hidden which is just not causing problems now?
Regards,
christian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当每个
.c
文件单独编译时,编译器知道的唯一信息就是您给出的函数原型。因为每个文件都是单独编译的,所以
main.c
的编译进程无法知道helper.c
中mean
的定义是错误的。.c
文件编译后,签名将被剥离,因此链接器也无法知道mean
是错误的。一个简单的修复方法是始终在实现
.c
文件中包含接口.h
文件,然后
helper.c
的编译过程会注意到不一致键入并警告您。When each
.c
file is compiled separately, the only information the compiler knows is the function prototype you have given.Because every file is compiled separately, there is no way the compiler process of
main.c
knows the definition ofmean
inhelper.c
is wrong.After the
.c
file is compiled, the signature will be stripped, so the linker cannot know themean
is wrong either.A simple fix is always include the interface
.h
file in the implementation.c
fileThen the compiler process of
helper.c
will notice that inconsistent type and warn you.平均值通常是实值,因此双倍即可。在这里,您将
mean
定义为返回 double,但原型为int Mean(...)
。gcc 能够意识到存在重新定义这一事实的唯一方法是,如果重新定义是真实发生的...当您单独编译文件时,可能会丢失平均原型...它至少不会显示在您的代码片段中:你应该将 helper.h 也包含到 helper.c 中。这样做时,
gcc -c helper.c
必须向您发出警告。我有 gcc 4.3.2,但我几乎可以肯定您所拥有的版本也一定如此。基本上,您只需使用mean
,因此这里 gcc 信任helper.h
中所说的内容。当您链接时,没有更多关于参数大小和返回值的信息,并且会发生不好的事情(例如将 int 读取为 double)。另一个细节:你说结构体的 int 得到 NaN...好吧,结构体中有一个 double,而 int 不能是 NaN!
A mean usually is a real value so double is ok. Here you define
mean
as returning double, but the prototype saysint mean(...)
.The only way gcc can be aware of the fact that there's a redefinition, is if the redefinition occurs for real... When you compile files separately likely the mean prototype is missing... it is not shown in your code fragment at least: you should include helper.h also into helper.c. Doing so,
gcc -c helper.c
must give you a warning. I have gcc 4.3.2, but I am almost sure it must be so also for the version you have. In the main, you just usemean
, so here the gcc trusts what is said inhelper.h
. When you link, there is no more information about the size of arguments and returning value, and bad things happen (like reading an int as a double).Another detail: you say you get NaN for an int of the struct... well, in the struct there's a double, and int can't be NaN!