gcc 编译C 报错集中

时间:2022-12-30 02:04:33

               

       为了让博客看一来更有干货,而不是一堆念念碎似得,这里把GCC编译C时遇到的一些报错和解决方案集中一下,有些报错比较傻,大家别笑话,由于时间问题就直接把原来的文章复制过来了,有点乱,其中还有一些我对错误的分析和看法。往后有其他的可能也会放到这里或是另开一篇文章。(如果代码出现了<span>等html标签请自行忽略,这是csdn自动加上的,可能是因为我用的Firefox吧)

1.在程序中使用了中文符号

SLinkList.c: In function ‘ListInsert’:
SLinkList.c:105:2: error: stray ‘\357’ in program
if(i < 1 || i > (ListLength(L) + 1) )
^
SLinkList.c:105:2: error: stray ‘\274’ in program
SLinkList.c:105:2: error: stray ‘\210’ in program
SLinkList.c:105:2: error: stray ‘\357’ in program
SLinkList.c:105:2: error: stray ‘\274’ in program
SLinkList.c:105:2: error: stray ‘\211’ in program

 问题分析:不是让人纠结的segment fault,不是傻逼的语法错误。一看也不知道哪里错了。google一看原来是使用了中文,其实我一直在尝试着用英文写注释,但是实在....


错误重现:知道了报错是中文的原因但是不知道是哪个字符用了中文。于是把附近的都重写了一边,报错消失了。为了测试我故意把分号改成了中文的分号,如期出现如下报错:

SLinkList.c: In function ‘ListInsert’:
SLinkList.c:106:3: error: stray ‘\357’ in program
return ERROR;
^
SLinkList.c:106:3: error: stray ‘\274’ in program
SLinkList.c:106:3: error: stray ‘\233’ in program
SLinkList.c:109:2: error: expected ‘;’ before ‘j’
j = Malloc_SL(L);


2.修改了原设不希望的变量

 warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]

这个警告是在写下面的程序时遇到的,程序的功能是自己实现strncpy函数并返回一个可继续利用的指针值


           char *strncpy(char *s,const char *t,int n) {
21   char *tmp;
22 tmp=s;
23 while(n) {
24 if( *tmp=*t) {
25 t++;
26 tmp++;
27 }
28 n--;
29 }
30 return s;
31 }

问题分析:由于t字符串不会在修改在函数参数上用了const增强代码的健壮性,编译时报上述错误,自己翻译应该是const类型被修改了,再一想const不就是不希望被修改吗,却又把它赋值给一个可修改的,故错误应该是出在tmp指针的类型上,上网一查还真是。

解决方案:tmp同样定义为const型 const char *tmp;
                 字符指针常量赋值给字符指针常量



3.自定义函数名和语言关键词冲突

warning:conflicting types for built-in function 

问题描述:今天在写strcpy等函数的具体实现时,碰到了这个

warning:conflicting types for built-in function ‘strcpy’ [enabled by default]
void strcpy(char *s,char *t);

void strcpy(char *s,char *t);


分析:按照字面意思毫无疑问是函数冲突,再看built-in应该是和C语言的内建函数重名冲突了。上网一查还真是。

在C语言标准中,有些通用函数被定义为built-in function(内建函数),像printf,puts,strchr,memset等等,这些函数不需要包含头文件中的声明,就可以编译连接该函数的。但有时候你想自己实现,就会出现上面所示的冲突提示。有的时候你不用包含一些头文件,也能使用那个里面包含的函数,可能是编译器包含了一些常用的简单的函数的处理。


解决办法:

1.在编译是加上-fno-builtn或者-fno-builtin-FUNCTION (FUNCTION指相应的函数名)选项,你就可以自己实现这些函数而不冲突了。例如在上面的提示中,你编译时加上-fno-builtin-puts ,就可以正常编译了。

2.把这些函数改个名称,以便不冲突。


参考:这个链接


4.函数没有声明就调用

conflicting types for xx

这个错误的原因可能不同

1.原来是因为没有先做函数声明,而函数位于main()之后。

2.头文件的被循环引用,在引用时考虑清楚包含顺序

3.头文件声明和定义参数稍有不同

例:

 头文件中声明 void Hanlder(constchar * buf);

 在定义时写作 void Hanlder(char *buf); 这是就会发生conflictingtypes for 错误问题


5.linux下编译程序包含了头文件却没有在编译选项中加上所要链接的库

undefined reference to `pow'  collect2: error: ld returned 1 exit status

    问题:写一个程序时用到pow()这个函数,gcc编译是出现错误, 提示说没有定义pow,可是已经包含了头文件<math.h>了,再次编译还是同样的错误

   分析: man 3 pow查看一下

gcc 编译C 报错集中


       解决:link with -lm 编译的时候要加上这个-lm选项,重新编译程序就OK了。库函数sin/cos等math.h中的使用都应该加上该选项进行编译。感觉还是用好好利用man page强大的功能的,还有就是好好学英语不然看都看不懂。


6.参数类型不一致报错

nvalid operands to binary % (have ‘double’ and ‘double’)

报错位置如下:

gcc 编译C 报错集中


分析:字面意思是不能两边都是double型的,可又必须要用double型的

解决这是因为%两侧都应该为整型常量故不能使用%,而应该使用库函数:double fmod(double x,double y)


7.缓冲区溢出(我想*是计算机科学里最有名的报错了)

  *** stack smashing detected ***: ./reverse terminated

Aborted (core dumped)

      由于不记得是哪个程序了的错误了(以后应该及时记下来的),就随便找了个程序段(程序的作用的通过递归翻转字符串,运行结果是"654321")来复现一下,如常用的交换位置的程序

    #include <stdio.h>  
#include <string.h>

int main() {
void reverse(char s[]);
char str[]="123456";
reverse(str);
printf("%s\n",str);
return 0;
}

void reverse(char s[]) {
void reverser(char s[],int i,int len);
reverser(s,0,strlen(s));
}
void reverser(char s[],int i,int len) {
int j=len-(i+1);
void swap(char s[],int i,int j);

if(i<j) {
<span style="color:#FF0000;">swap(s,i,j);
reverser(s,++i,len);
}
}

void swap(char s[],int i,int j) {
char ch;
ch=s[i];
s[i]=s[j];
s[j]=ch;
}

        分析:假设将 swap(s,i,j) 改为 swap(s,i,j+3)  这里是为了复现错误故意改的,编译会正常通过,但执行时会出现上面的报错。这是因为C语言比较“宽松、灵活,语法检查不严格”,在遇到数组越界、栈溢出等问题时编译时不会报出来,等到运行时才知道有这个错!当然也有可能不会报错。这里的报错原因明显的是因为数组下标越界所致,使栈溢出了


补充:

        对“栈溢出”(也称缓存区溢出),需要一些对策。比如GCC的“Stack-Smashing Protector”机制(在数组后插入一些金丝雀(Canary, 因为大家在矿井作业时,会用金丝雀来预警,如果金丝雀死了,那证明有毒气),在函数执行完成返回之前会检查一下Canary,如果canary被改掉,则不再继续执行,中止程序,避免执行攻击者的代码。)出现“栈溢出”这个错,实际上是GCC编译器的保护作用。


尝试了编译时怎么不开启"Stack-Smashing Protector"。(“Stack-Smashing Protector”默认是打开的!)

如:$ gcc -g reverse.c -o reverse -fno-stack-protector。运行时输出结果后不会报“stack smashing detected”!

-g选项是为了加入调试信息,方便用gdb调试。

原来的报错:

gcc 编译C 报错集中


关掉保护机制后,执行:

gcc 编译C 报错集中

关于哪个乱码我也不知道是什么,如果有大牛知道望告知(我使用的系统:ubuntu 14.04 LTS 没有汉化)。


8.Segmentation fault (core dumped)

         我想这个报错你绝不会感到陌生,鉴于篇幅有限具体的分析和解决我放在另外的一篇文章中了,因为里面还介绍了调试和解决这个报错的方法。Segmentation fault


总结:bug啊bug你在哪里,bug啊bug你到底怎么才能不再出现,愿下一个程序No Warning  No Error(这怎么可能呢!!!)


本博客持续更新,欢迎大家的指正!