警惕编译器的警告 - 一次印象深刻的调试

警惕编译器的警告warning


最近coding时遇到一个函数返回值的问题,问题发生的比较隐蔽,记录一下。

我是在64位机器上去编译一个64位的程序,代码刚敲好,也比较乱,迫不及待的去编译一下。make一看居然通过了,顿时感觉比较兴奋,虽然warning也不计其数。。
于是急切的想测试一下程序是否work,果不其然segment fault。。
于是开始调试起来,一直没有关心那一堆编译器语重心长的warning,调试的结果让我悔恨不已。

通过log我发现一个函数的返回值有问题,但仔细检查了逻辑并无不妥,代码如下:

#define QUEUE_TYPE  stack_msg_t*
static QUEUE_TYPE queue[QUEUE_SIZE];

QUEUE_TYPE get_queue_head()
{
  if(queue_empty())
    return NULL;
  return queue[qhead];
}

无奈动用gdb去单步调试,发现queue[qhead]的值是正确的,为一个64bit的指针,指向内存的内容也是正确的。但当这个函数返回后,赋值给一个变量,诡异的事情就发生了。这个指针的值被截取了一半,变成32bit了。赋值的代码也很简单:

stack_msg_t *msg = get_queue_head();

在get_queue_head函数返回的时候我打印了返回值为0x0006 0000abc0, 但是出了这个函数赋值给msg这个指针后,msg的值却是0x0000abc0. 我又确认了一下sizeof(stack_msg_t *)为8,没错,sizeof(queue[qhead])也是8,也没错啊。

没办法,2条C代码之间出了奇怪的问题只好硬着头皮看汇编了。于是发现这个函数返回的时候确实将64bit数据放进寄存器中,但在函数调用完后,调用此函数的地方只取了32bit数据并赋值给msg变量,msg变量本身却是64bit的。编译器为何要这样做呢?

google了一番,刚好碰到一个和我类似问题的网友,下面几个回复也是没有说到点子上。但最后那个网友回复了一句“加上函数声明就好了”。我一下子醒悟过来。。

C语言在函数没有声明的情况下虽然也可以调用,编译器也不会报错,只是给出警告。真正的问题在于,编译器在处理调用函数部分的代码时是无法判断这个函数的类型的。也就是说编译器只管把真实的参数压栈,然后跳到函数内部,等函数返回后再拿到返回值,至于是不是和函数定义的参数类型、返回值匹配,编译器是不会检查的。而且此时编译器会默认返回值为int类型。而sizeof(int)为4.

这就解释了为什么会出现之前的诡异现象,同时也说明了正视编译器warning是一件多么重要的事情。。。

以前编译各类程序,别人的或自己的,经常出现一堆warning,也没有在意,反而觉得编译器啰嗦。而实际使用中往往也没有出现任何问题,这让我们逐渐习惯了对warning的视而不见。其实真正的bug一直潜伏在代码里面,只等一个机会来证明自己。。

贴一个最近编译的某厂android代码中的warning:

warnings building an Android project

你可能感兴趣的:(警惕编译器的警告 - 一次印象深刻的调试)