10 C语言的妖怪!隐式声明

2019-03-11  本文已影响0人  Savior2016

缘起

相传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就可以找到所有隐式声明的函数,再到提示中的文档里包含以下头文件或者添加一下声明就好了:

declared implicitly
上一篇下一篇

猜你喜欢

热点阅读