报错storage size of ‘act’ isn’t known当使用std=c99编译struct sigaction
2016-03-27 16:10
666 查看
问题
今天在学习进程间通信之-信号signal–linux内核剖析(九)遇见了一个奇怪的问题
storage size of ‘oldact’ isn’t known
于是FQ去google之。
分析了好久,终于发现问题的原因了。于是记录下来
发现
测试的代码如下#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <bits/sigaction.h> int main() { struct sigaction act; return 0; }
gcc test.c按照默认进行编译,无错误
gcc test.c -std=gnu99和
gcc test.c -std=gnu9x无错
gcc test.c -std=c99出错
gcc test.c --ansi出错
原因解析
参见 sigaction() and ANSI C======
because sigaction is a POSIX system call.
Maybe so, but it isn’t part of ANSI-C
Generally, you need to isolate system dependencies in as few places as possible, so that most of your code can be compiled with -ansi
If you dance barefoot on the broken glass of undefined behaviour, you’ve got to expect the occasional cut.
If at first you don’t succeed, try writing your phone number on the exam paper.
======
Am I right in thinking then that -ansi sets something that makes the preprocessor ignore the non ANSI standard parts of signal.h?
Yes.
Things which are not in ANSI-C get excluded when you specify -ansi, simply because they’re not guaranteed to be everywhere else. Regard -ansi as a strict portability checker.
because it is required to run on several different flavours of UNIX.
Perhaps you should relax the test a little bit, down to POSIX compatibility. That should allow you to port your code easily to most unices (plural of unix), and still use sigaction() since it is part of POSIX.
If you can’t manage ANSI, at least POSIX is a good 2nd choice to go for.
If you have many source files, you should be able to arrange for nearly all of them to be compiled with -ansi, and just a few which rely on POSIX. That way, any porting surprises you do have will be localised in just a few places.
If you dance barefoot on the broken glass of undefined behaviour, you’ve got to expect the occasional cut.
If at first you don’t succeed, try writing your phone number on the exam paper.
-std=c99 problem with signal.h
Actually if you want strict ansi/c99 compliance, you should use “signal” instead of “sigaction” which is defined by POSIX.1-2001.
In fact POSIX.1 supports both but prefers “sigaction”, whereas ansi/c99 supports only “signal”.
Of course, “signal” is very much system dependent.
See “man signal”, “man sigaction”.
The following link has a lot of information.
https://www.securecoding.cert.org/confluence/display/seccode/SIG00-C.+Mask+signals+handled+by+noninterruptible+signal+handlers
其实说的很明晰了,就是说signal是一个ansi/C99编译器支持的函数,sigaction是后来在POSIX.1-2001中新增的接口,那么由于向前兼容的特性,ansi/c99并不支持sigaction函数接口。
也就是说,大多数操作系统均支持signal,但是却只有部分支持sigaction。
因此编译器在处理的时候,如果你指定了–ansi或者-std=c99的指令后,编译器会认为你要是编译一个标准的C程序,那么就在编译时(准确的来说是预处理阶段)将你不符合C标准的地方舍弃掉,
怎么舍弃呢?当然是通过宏了。
验证
我们知道gcc编译器可以通过-E来进行预处理来生成预处理后的文件。那么我们现在来验证一下子,我们在生成的预处理文件中,搜索指定的sigaction关键字,看预处理的文件中,有没有该结构体的定义
gcc -E test.c -std=c99 | grep sigaction gcc -E test.c --ansi | grep sigaction
很明显,我们指定了使用C标准的编译器后,编译器在预处理阶段针对非C标准的接口都屏蔽掉了。
同样我们使用GNU编译器扩展的C编译器进行预处理,看看有什么
gcc -E test.c -std=gnu99 | grep sigaction gcc -E test.c -std=gnu9x | grep sigaction
好了,我们现在是不是很清楚了
关于具体gcc编译参数的详情,请参见GCC Command-Line Options
我们可以看到–ansi指定使用古老的标准ansiC标准编译,-std=c99则指定使用新的C99标准编译,而
gnu99和
gnu9x则是gcc编译器对C99标准自己的实现
这些的关系是什么呢,
首先标准委员会指定了语言的标准,也就是ansi和后来的C88,C99标准
但是只有标准怎么行,必须有编译器来支持啊,于是各个编译器都开始逐步支持新的标准,同时也就是出现了-std=c89,-stdc99,为了兼容之前的程序,而保留旧的标准–ansi
但是对标准的支持,不可能一下子,只实现了一部分,慢慢再进行扩展,另外由于标准中某些地方可能并不实用,可能需要一些扩展,于是出现了-std=gnu99,现在很多编译器对C的语法都有一些不同的扩展,而这些扩展有些已经加入了新的标准中,有些并未加入或者正在议案加入。
解决
解决方法1
就是我们在编译的过程中编译器的类型,比如-std=gnu99解决方法2
在#include <signal.h>之后显式添加sigaction的头文件
#include <bits/sigaction.h>
这样编译器会显式的编译sigaction的定义
但是这种情况下需要注意,
#include <bits/sigaction.h>必须在
#include <signal.h>之后
因为
signal中会通过
#error进行预处理,检查`bits/sigaction.h是否包含,
如果用户没有包含的话,预处理阶段就会报错
#error "Never include <bits/sigaction.h> directly; use <signal.h> instead."
相关文章推荐
- Linux Kernel 4.0 RC5 发布!
- 如何组织构建多文件 C 语言程序(二)
- 谷歌正式开始补偿Nexus 6P重启门和电池门用户:最高赔400美元
- 如何写好 C main 函数
- C#实现子窗体与父窗体通信方法实例总结
- 谷歌、雅虎支持中文域名搜索 有助提升搜索引擎优化
- C#中struct和class的区别详解
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- java和c#使用hessian通信的方法
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总