strerror&gcc -W&__FILE__

内容:

1、strerror使用导致的Segmentation fault (core dumped)
2、strerr和strout的区别
3、gcc的-Wall和-W参数
4、__FILE__和__LINE__


1. strerror使用导致的Segmentation fault (core dumped)

在运行一段网上的代码的时候发现strerror函数返回的值并没有打印出来,而是出现了Segmentation fault (core dumped)

代码如下:

#include <pthread.h>
#include <stdio.h>
#include <errno.h>

int main (int argc, char *argv[])
{
    pthread_t thread;
    int status;

    status = pthread_join (thread, NULL);
    if (status != 0)
        fprintf (stderr, "error %d: %s\n", status, strerror (status));
    return status;
}

以上的代码编译时出现:

warning: format ‘%s’ expects argument of type ‘char *’, but argument 4 has type ‘int’ [-Wformat=]
fprintf (stderr, “error %d: %s\n”, status, strerror (status));
^

但是,当时由于编译通过了,我并没有在意这个warning;
而在运行该文件时,出现了

Segmentation fault (core dumped)

解决:

其实解决的思路已经包含在warning中了。
在使用gcc -Wall时:

warning: implicit declaration of function ‘strerror’ [-Wimplicit-function-declaration]
fprintf (stderr, “error %d: %s\n”, status, strerror (status));
^

由此看来在使用gcc编译时,加上-Wall选项是多么重要。

但是,为什么之前的warning会出现呢?
首先,在c语言中,函数声明称为函数原型(function prototype)。它的主要作用是利用它在程序的编译阶段对调用函数的合法性进行全面检查。
通常,如果在函数调用前,没有对函数作声明,则编译系统会把第一次遇到的该函数形式(函数定义或函数调用)作为函数的声明,并将函数类型默认为int 型。

因此,在编译过程中,由于没有包含strerror()的头函数”string.h”,strerror()在调用之前没有进行函数声明,编译时首先遇到了“strerror (status)”,由于对原型的处理是不考虑参数名的,因此系统将strerror()加上int作为函数声明,即int strerror();

而在链接阶段中,并没有找到该函数的定义,所以报错。

那么,为什么会最终会出现Segmentation fault (core dumped)的错误?

由于,我的系统是64位,而64位系统中的char*是64位,而int是32位,所以我使用32位的整形值作为地址赋值给了指针,所以指针指向了非法内存,所以出现了Segmentation fault (core dumped)错误。

总结:
1. strerror()函数是声明在string.h头文件中;
2. gcc编译时,如果发现未定义的函数,会认为函数时定义在其他源文件中的,所以编译通过了。

参考文章:
1. http://www.cnblogs.com/acool/p/4708483.html
2. http://blog.csdn.net/zhongguoren666/article/details/8477908



2. gcc的-Wall和-W参数

吸取上面的教训,在使用gcc编译的时候,使用-Wall -W。
因此,记录一下-Wall参数的使用。

-Wall : 编译后显示所有警告。
-W : 类似-Wall,会显示警告,但是只显示编译器认为会出现错误的警告。(这里是大写)
-w : 关闭编译时的警告,也就是编译后不显示任何warning。(这里是小写)

具体有哪些警告可以参考文章2.

想要使用-Wall来启用个选项,同时又要关闭某洲警告,比如unused警告,可以使用如下命令:

$gcc -Wall -Wno-unused test.c -o test

参考文章:
1. http://blog.csdn.net/m7548352/article/details/49520069
2. http://blog.sina.com.cn/s/blog_553230d70101efqv.html



3. stderr和stdout的区别

stderr : 标准错误
stdout : 标准输出

有2点区别:
1. stdout是行缓冲,而stderr是无缓冲
2. 两者默认向屏幕输出。 但如果用转向标准输出到磁盘文件,stdout输出到磁盘文件,stderr在屏幕

以下摘自参考文章1:
1,我们知道,标准输出和标准错误默认都是将信息输出到终端上,那么他们有什么区别呢?让我们来看个题目:

问题:下面程序的输出是什么?(intel笔试2011)

int main(){
fprintf(stdout,"Hello ");
fprintf(stderr,"World!");
return0;
}

解答:这段代码的输出是什么呢?你可以快速的将代码敲入你电脑上(当然,拷贝更快),然后发现输出是

World!Hello

这是为什么呢?在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲的,会直接输出,举例来说就是printf(stdout, “xxxx”) 和 printf(stdout, “xxxx\n”),前者会憋住,直到遇到新行才会一起输出。而printf(stderr, “xxxxx”),不管有么有\n,都输出。

2、这3句效果有什么区别吗?

fprintf(stderr, "Can't open it!\n"); 
fprintf(stdout, "Can't open it!\n"); 
printf("Can't open it!\n"); 

有区别。
stdout – 标准输出设备 (printf(“..”)) 同 stdout。
stderr – 标准错误输出设备
两者默认向屏幕输出。
但如果用转向标准输出到磁盘文件,则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕。

例如:
my.exe
Can’t open it!
Can’t open it!
Can’t open it!

转向标准输出到磁盘文件tmp.txt
my.exe > tmp.txt
Can’t open it!

用TYPE 看 tmp.txt的内容:
TYPE tmp.txt
Can’t open it!
Can’t open it!

参考文章:
1. http://blog.csdn.net/origin_lee/article/details/41576975



4. __FILE__和__LINE__

以下内容摘自参考文章1:

编译器内置宏:

先介绍几个编译器内置的宏定义,这些宏定义不仅可以帮助我们完成跨平台的源码编写,灵活使用也可以巧妙地帮我们输出非常有用的调试信息。

ANSI C标准中有几个标准预定义宏(也是常用的):

__LINE__:在源代码中插入当前源代码行号;
__FILE__:在源文件中插入当前源文件名;
__DATE__:在源文件中插入当前的编译日期
__TIME__:在源文件中插入当前编译时间;
__STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;
__cplusplus:当编写C++程序时该标识符被定义。

编译器在进行源码编译的时候,会自动将这些宏替换为相应内容。

看到这里,你的眼睛应该一亮了吧,嗯,是的,__FILE__和__LINE__正是我们前面想要的输出的,于是,我们的每一条语句都变成了:

DEBUG(“FILE: %s, LINE: %d…”,__FILE__,__LINE__,…)

其实没有必要,__FILE__本身就会被编译器置换为字符常量,于是乎我们的语句又变成了这样:

DEBUG(“FILE:”__FILE__”, LINE: %d…”,__LINE__,…)

但是,我们还是不满足,依然发现,还是很讨厌,为什么每条语句都要写”FILE:”__FILE__”, LINE: %d 以及__LINE,这两个部分呢?这不是浪费我们时间么?

这就是本次大结局,把DEBUG写成这样:

DEBUG(format,…) printf(“FILE: “__FILE__”, LINE: %d: “format”/n”, __LINE__, ##__VA_ARGS__)

下面,所有的DEBUG信息都会按照这样的方式输出:

FILE: xxx, LINE: xxx, …….

#define __DEBUG__  
#ifdef __DEBUG__  
#define DEBUG(format,...) printf("File: "__FILE__", Line: %05d: "format"/n", __LINE__, ##__VA_ARGS__)  
#else  
#define DEBUG(format,...)  
#endif  
int main() {  
    char str[]="Hello World";  
    DEBUG("check: %s",str);  
    return 0;  
}  

输出为:

File: test.c, Line: 00013: check: Hello World

参考文章:
1. http://www.cnblogs.com/lixiaohui-ambition/archive/2012/08/21/2649052.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值