美文网首页
10 C语言的妖怪!隐式声明

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

作者: Savior2016 | 来源:发表于2019-03-11 13:10 被阅读0次

    缘起

    相传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

    相关文章

      网友评论

          本文标题:10 C语言的妖怪!隐式声明

          本文链接:https://www.haomeiwen.com/subject/fhwspqtx.html