缘起
相传2019年3月8日女神节,天降暴雨。在一个年轻程序员的电脑里,发生了一件奇异的事……
他写了这样一个函数:
u32 UnionFloatToU32(float ordata)
{
union convert
{
u32 u32data;
float floatdata;
} con;
con.floatdata=ordata;
return con.u32data;
}
函数内容不重要,主要是形参是float类型,这日后导致了悲剧的发生。
他进行了这样的调用:
void OSStackThread(mico_thread_arg_t arg)
{
u32 ctest=0;
double testfl=123.99; //double是在测试过程中改的,本来是float,下面懒得重新截图,跟float现象是一样的
UNUSED_PARAMETER(arg);
while (true)
{
ctest=UnionFloatToU32(testfl);
mico_thread_msleep(2000);
}
}
什么?!他想把一个float直接放在一个32位的变量中存储起来?这……有什么价值?
这也不重要,重要的是悲剧就此发生了。
打断点,发现ctest是0?!
ctest
进函数看看:
形参
传进来的形参就是0?!
很灵异是不是,在网上查,很多人说float类型有问题,编译器有bug,建议使用全局变量传参。
直觉告诉我,他们是骗子。
真相只有一个
参考文献:万恶之源:C语言中的隐式函数声明
简单点说,就是c编译器,遇到文件中可以找到的函数(暂时不清楚为什么不报函数未定义,编译器能在其他文件中找到),但是没有进行声明或者没有包含声明函数的头文件,这个时候,c编译器会自己给其增加一个固定格式的声明,以保证程序能够“顺利”完成编译(所以不能保证正常运行有啥用),然后警告你一下。
关键问题在于这个自行增加的声明,它只知道要给你声明形参,但是却不知道形参类型,只知道函数名以及你有几个形参。于是就根据你的调用情况,默认给你安排了int类型的形参(我感觉也可能是其他类型)。特别是把float安排错的时候,就会引发参数传递错误的问题。但是这个错误的值,经过我的多次试验,也不清楚为什么会成为0,有没有什么原理。如果谁知道了怎么回事麻烦告诉我一下。
避免办法
可以在工程上右键,重新编译工程,然后全选build框里面的编译信息.。复制到别的文件中,比如在vs code中新建一个文件,粘贴进去。
然后搜索declared implicitly
就可以找到所有隐式声明的函数,再到提示中的文档里包含以下头文件或者添加一下声明就好了:
网友评论