报错storage size of ‘sa’ isn’t known,当使用std=c99编译struct sigaction

简介: 报错storage size of ‘sa’ isn’t known,当使用std=c99编译struct sigaction
void signal_exit_func(int signo)
{
    printf("exit signo is %d\n", signo);
    //CSingleton<CNet_TCPServer>::instance().stop_server();
}
void signal_exit_handler()
{
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_exit_func;
    sigaction(SIGINT, &sa, NULL);//当按下ctrl+c时,它的效果就是发送SIGINT信号
    sigaction(SIGTERM, &sa, NULL);//kill pid
    sigaction(SIGQUIT, &sa, NULL);//ctrl+\代表退出SIGQUIT
    //SIGSTOP和SIGKILL信号是不可捕获的,所以下面两句话写了等于没有写
    sigaction(SIGKILL, &sa, NULL);//kill -9 pid
    sigaction(SIGSTOP, &sa, NULL);//ctrl+z代表停止
    //#define    SIGTERM        15
    //#define    SIGKILL        9
    //kill和kill -9,两个命令在linux中都有杀死进程的效果,然而两命令的执行过程却大有不同,在程序中如果用错了,可能会造成莫名其妙的现象。
    //执行kill pid命令,系统会发送一个SIGTERM信号给对应的程序。
    //执行kill -9 pid命令,系统给对应程序发送的信号是SIGKILL,即exit。exit信号不会被系统阻塞,所以kill -9能顺利杀掉进程。
}

本人编译报错:error: storage size of ‘sa’ isn’t known


    struct sigaction sa;


解决方法是:新添加头文件bits/sigaction.h即可。


#include <signal.h>

#include <bits/sigaction.h>




-----


参考文章:https://blog.csdn.net/gatieme/article/details/50991903


问题


今天在学习进程间通信之-信号signal–linux内核剖析(九)

遇见了一个奇怪的问题


storage size of ‘oldact’ isn’t known

1

1

于是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按照默认进行编译,无错误

image.png

  • gcc test.c -std=gnu99gcc test.c -std=gnu9x无错

image.png

  • gcc test.c -std=c99出错

image.png

  • gcc test.c --ansi出错

image.png

原因解析


参见 sigaction() and ANSI C

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


image.png


很明显,我们指定了使用C标准的编译器后,编译器在预处理阶段针对非C标准的接口都屏蔽掉了。


同样我们使用GNU编译器扩展的C编译器进行预处理,看看有什么


gcc -E test.c -std=gnu99  | grep sigaction

gcc -E test.c -std=gnu9x  | grep sigaction

image.png



好了,我们现在是不是很清楚了


关于具体gcc编译参数的详情,请参见GCC Command-Line Options


image.png


我们可以看到–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>  

1

1

这样编译器会显式的编译sigaction的定义


但是这种情况下需要注意,#include <bits/sigaction.h> 必须在#include <signal.h>之后


因为signal中会通过#error进行预处理,检查`bits/sigaction.h是否包含,

如果用户没有包含的话,预处理阶段就会报错


#error "Never include <bits/sigaction.h> directly; use <signal.h> instead."

image.png


版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatiemehttps://blog.csdn.net/gatieme/article/details/50991903


相关文章
|
Ubuntu Linux 编译器
openssl 的编译(linux、Ubuntu) 和 交叉编译(arm、Hi3531A)的问题分析、解决
openssl 的编译(linux、Ubuntu) 和 交叉编译(arm、Hi3531A)的问题分析、解决
3228 0
|
Linux
`grep`命令搜索当前目录及其子目录下的所有文件
`grep`命令搜索当前目录及其子目录下的所有文件
6934 1
Beyond Compare 4密钥过期解决办法,超实用
Beyond Compare 4密钥过期解决办法,超实用
31935 1
|
Shell Linux Android开发
【Linux】【编译相关】execvp: /bin/sh: Argument list too long问题处理小结
【Linux】【编译相关】execvp: /bin/sh: Argument list too long问题处理小结
2657 0
|
IDE 编译器 开发工具
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
在本文中,我们系统地讲解了常见的 `#pragma` 指令,包括其基本用法、编译器支持情况、示例代码以及与传统方法的对比。`#pragma` 指令是一个强大的工具,可以帮助开发者精细控制编译器的行为,优化代码性能,避免错误,并确保跨平台兼容性。然而,使用这些指令时需要特别注意编译器的支持情况,因为并非所有的 `#pragma` 指令都能在所有编译器中得到支持。
1673 41
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
|
9月前
|
Web App开发 Ubuntu 算法
Ubuntu 20.04 LTS 版本发布,新特性、新布局
Ubuntu 20.04 LTS借助新的内核压缩算法,具有更快的启动速度,并带有大量新的图形驱动程序、软件和实用程序,使用体验会更好。
746 0
|
Linux 编译器 C语言
Linux EXPORT_SYMBOL宏详解
Linux EXPORT_SYMBOL宏详解
Linux EXPORT_SYMBOL宏详解
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
1025 6
|
监控 安全 Ubuntu
Linux内核升级指南####
本文将深入探讨Linux操作系统的内核升级过程,旨在为系统管理员和高级用户提供一份详尽的操作指南。通过分析升级前的准备、升级过程中的关键步骤以及升级后的配置优化,本文旨在帮助读者安全、高效地完成内核升级,从而提升系统性能和安全性。 ####
1237 7