原来函数入参类型不匹配gcc也能编译通过啊

背景

前一段时间赶工修一个段错误的BUG,修复后代码不再有段错误,但却会导致板子软件与上位机断链,而且还是概率性的。
经过一周的排查,原来是修BUG时引入一个传参错误,给期待struct *形参的函数传了个struct **的实参,导致踩内存,又因为赶工,没仔细看编译告警,于是坑了自己。

复现过程

复现代码:

#include<stdio.h>

void change_info(int *p)  // 形参期待一级指针
{
    *p = 42;
}

int main() {
    int a = 0;
    int *pa = &a;

    printf("a == %d\n", a);
    change_info(&pa);  // 实参传递二级指针,会导致内存访问越界,即踩内存!
    printf("a == %d\n", a);
    return 0;
}

上面代码gcc编译通过,但有告警,说指针类型不匹配:

isp@ax:~/demo$ gcc test_2nd_ptr2.c
test_2nd_ptr2.c: In function ‘main’:
test_2nd_ptr2.c:13:17: warning: passing argument 1 of ‘change_info’ from incompatible pointer type [-Wincompatible-pointer-types]
     change_info(&pa);
                 ^
test_2nd_ptr2.c:3:6: note: expected ‘int *’ but argument is of type ‘int **’
 void change_info(int *p)
      ^~~~~~~~~~~

如果编译的文件很多,很容易忽略这些告警

上面问题代码的运行效果:

isp@ax:~/demo$ ./a.out
a == 0
a == 0

如何规避

  1. 用g++编译器无此问题,直接报error
isp@ax:~/demo$ g++ test_2nd_ptr2.c
test_2nd_ptr2.c: In function ‘int main()’:
test_2nd_ptr2.c:13:18: error: invalid conversion from ‘long long int’ to ‘int*’ [-fpermissive]
     change_info(l);
                  ^
test_2nd_ptr2.c:3:6: note:   initializing argument 1 of ‘void change_info(int*)’
 void change_info(int *p)
      ^~~~~~~~~~~
test_2nd_ptr2.c:15:20: error: cannot convert ‘int**’ to ‘int*’ for argument ‘1’ to ‘void change_info(int*)’
     change_info(&pa);
                    ^
  1. 给gcc传递-Werror选项也能避免此问题
isp@ax:~/demo$ gcc -Werror test_2nd_ptr2.c
test_2nd_ptr2.c: In function ‘main’:
test_2nd_ptr2.c:13:17: error: passing argument 1 of ‘change_info’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     change_info(&pa);
                 ^
test_2nd_ptr2.c:3:6: note: expected ‘int *’ but argument is of type ‘int **’
 void change_info(int *p)
      ^~~~~~~~~~~
cc1: all warnings being treated as errors
  1. 给指针字段添加p_之类的前缀,便于提醒自己

后记

我试了好几种不兼容的指针类型传递,都能编译通过,可见只要参数size匹配就不会报错。
对于非指针类型的参数,一般情况下size不同,此时会报错,但如果是内置类型,则size不同也不会报错,因为会自动向上取整或截断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当我们使用gcc编译代码时,如果出现了头文件报错的情况,一般有以下几种可能性: 1. 头文件路径错误:编译器无法找到指定的头文件。这可能是因为我们在include语句中指定的路径有误,或者头文件没有正确地放置在指定路径下。我们应该检查include语句中的路径是否正确,并确保头文件存在于指定的路径中。 2. 头文件缺失:有时我们可能会忽略了某个必要的头文件。如果我们在代码中使用了某个库或其他文件的函数类型,但是忘记了包含相应的头文件,编译器会报错。解决方法是查找并包含所需的头文件。 3. 头文件名字拼写错误:如果我们在include语句中拼写错误,或者文件名与实际头文件不匹配编译器会抱错。我们应该仔细检查include语句中的文件名拼写,并与实际的头文件进行比对。 4. 头文件冲突:当我们在不同的库或模块中使用相同的头文件名时,可能会出现头文件冲突。这就意味着编译器无法确定应该使用哪个头文件。为了解决这个问题,我们可以使用全局的唯一命名约定或者重命名冲突的头文件。 5. 编译器选项错误:有时使用错误的编译器选项也会导致头文件报错。我们应该确保使用了正确的编译器选项,并查看编译器文档以了解正确的选项和用法。 当头文件报错时,我们应该仔细检查上述可能性,并根据实际情况进行排除和解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值