0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言开发中可能会用到的GNU

Q4MP_gh_c472c21 来源:开源博客 作者:-_-struggle 2021-11-17 10:41 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

为了方便使用,GNU C在标准C语言的基础上进行了部分方便开发的扩展。

这里讲解一些开发中可能会用到的,或者使用频率比较高的内容。

零长度数组和变量长度数组

GNU C 允许使用零长度数组,比如:

char data[0];

GNU C 允许使用一个变量定义数组的长度如:

int n=0;
scanf("%d",&n);
int array[n];

case 范围

GNU C支持 case x...y这样的语法,[x,y]之间数均满足条件。

case 'a'...'z':  /*from 'a' to 'z'*/
break;

语句表达式


GNU C 把包含在括号中的复合语句看作是一个表达式,称为语句表达式。

 #define min_t(type,x,y)
         ({type __x=(x); type __y=(y);__x<__y?__x:__y;})

这种写法可以避免:

 #define min_t(x,y) ((x)<(y)?(x):(y))

在min_t(x++,++y)中出现的副作用。

typeof 关键字

typeof(x)可以获得x的类型借助typeof关键字我们可以重新定义min_t:

#define min_t(x,y)
    ({typeof(x) __x=(x); typeof(y) __y=(y);__x<__y?__x:__y;})

可变参数宏

GNU C中宏也支持可变参数:

#define pr_debug(fmt,arg...) 
        printk(fmt,##arg)

这里,如果可变参数被忽略或为空,“##”操作将使预处理器去掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU C也会工作正常,它会把这些可变参数放到逗号的后面。

标号元素

标准C要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C中,通过指定索引或结构体成员名,允许初始化以任意顺序出现。

unsigned char data[MAX] =
{
         [0]=10,
         [10]=100,
};


struct file_operations ext2_file_operations=
{
        open:ext2_open,
        close:ext2_close,
};

linux 2.6中推荐如下方式:

struct file_operations ext2_file_operations=
{
     .read=ext2_read,
     .write=ext2_write,
};

当前函数名

GNU C中预定义两个标志符保存当前函数的名字,__ FUNCTION __ 保存函数在源码中的名字, __ PRETTY__ FUNCTION __保存带语言特色的名字。在C函数中这两个名字是相同的。

void func_example()
{
     printf("the function name is %s",__FUNCTION__);
}

在C99中支持__ func __ 宏,因此建议使用 __ func __ 替代 __ FUNCTION __ 。

特殊属性声明

GNU C 允许声明函数、变量和类型的特殊属性,以便进行手工的代码优化和定制。如果要指定一个属性声明,只需要在声明后添加__ attribute __((ATTRIBUTE))。其中ATTRIBUTE为属性说明,如果存在多个属性,则以逗号分隔。GNU C 支持noreturn,noinline, always_inline, pure, const, nothrow, format, format_arg, no_instrument_function, section, constructor, destructor, used, unused, deprecated, weak, malloc, alias warn_unused_result nonnull等十个属性。

noreturn属性作用于函数,表示该函数从不返回。这会让编译器优化代码并消除不必要的警告信息。例如:

#define ATTRIB_NORET __attribute__((noreturn)) ....
asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;

packed属性作用于变量和类型,用于变量或结构域时,表示使用最小可能的对齐,用于枚举、结构或联合类型时表示该类型使用最小的内存。如对于结构体,就是它告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。例如:

struct example_struct
{
         char a;
         int b;
         long c;
} __attribute__((packed));

regparm属性用于指定最多可以使用n个寄存器(eax, edx, ecx)传递参数,n的范围是0~3,超过n时则将参数压入栈中(n=0表示不用寄存器传递参数)。

注意:以上这些属性都是在X86处理器体系结构下的,在X64体系结构下,大部分内容都是同样有效的。但是,这里要注意regparm属性,由于在X64体系结构下,GUN C的默认调用约定使用寄存器传递参数。所以,如果regparm属性里使用的寄存器个数超过3个,也仍然会使用其他寄存器来传递参数。这一点要遵循X64体系结构的调用约定。

下面可以看一个例子:

int q = 0x5a;
int t1 = 1;
int t2 = 2;
int t3 = 3;
int t4 = 4;
#define REGPARM3 __attribute((regparm(3)))
#define REGPARM0 __attribute((regparm(0)))
void REGPARM0 p1(int a)
{
     q = a + 1;
}


void REGPARM3 p2(int a, int b, int c, int d)
{
     q = a + b + c + d + 1;
}


int main()
{
    p1(t1);
    p2(t1,t2,t3,t4);
    return 0;
}

使用objdump命令反汇编,相关命令如下:

objdump -D 可执行程序

其中-D选项用于反汇编所有的程序段,包括:代码段、数据段、只读数据段以及一些系统段等等。而-d命令只反汇编代码段的内容。

反汇编后的关键代码如下:

Disassembly of section .text:
0000000000400474 :
  400474:    55                       push   %rbp
  400475:    48 89 e5                 mov    %rsp,%rbp
  400478:    89 7d fc                 mov    %edi,-0x4(%rbp)
  40047b:    8b 45 fc                 mov    -0x4(%rbp),%eax
  40047e:    83 c0 01                 add    $0x1,%eax
  400481:    89 05 3d 04 20 00        mov    %eax,0x20043d(%rip)        # 6008c4 
  400487:    c9                       leaveq 
  400488:    c3                       retq   


0000000000400489 :
  400489:    55                       push   %rbp
  40048a:    48 89 e5                 mov    %rsp,%rbp
  40048d:    89 7d fc                 mov    %edi,-0x4(%rbp)
  400490:    89 75 f8                 mov    %esi,-0x8(%rbp)
  400493:    89 55 f4                 mov    %edx,-0xc(%rbp)
  400496:    89 4d f0                 mov    %ecx,-0x10(%rbp)
  400499:    8b 45 f8                 mov    -0x8(%rbp),%eax
  40049c:    8b 55 fc                 mov    -0x4(%rbp),%edx
  40049f:    8d 04 02                 lea    (%rdx,%rax,1),%eax
  4004a2:    03 45 f4                 add    -0xc(%rbp),%eax
  4004a5:    03 45 f0                 add    -0x10(%rbp),%eax
  4004a8:    83 c0 01                 add    $0x1,%eax
  4004ab:    89 05 13 04 20 00        mov    %eax,0x200413(%rip)        # 6008c4 
  4004b1:    c9                       leaveq 
  4004b2:    c3                       retq   


00000000004004b3 
: 4004b3: 55 push %rbp 4004b4: 48 89 e5 mov %rsp,%rbp 4004b7: 53 push %rbx 4004b8: 8b 05 0a 04 20 00 mov 0x20040a(%rip),%eax # 6008c8 4004be: 89 c7 mov %eax,%edi 4004c0: e8 af ff ff ff callq 400474 4004c5: 8b 0d 09 04 20 00 mov 0x200409(%rip),%ecx # 6008d4 4004cb: 8b 15 ff 03 20 00 mov 0x2003ff(%rip),%edx # 6008d0 4004d1: 8b 1d f5 03 20 00 mov 0x2003f5(%rip),%ebx # 6008cc 4004d7: 8b 05 eb 03 20 00 mov 0x2003eb(%rip),%eax # 6008c8 4004dd: 89 de mov %ebx,%esi 4004df: 89 c7 mov %eax,%edi 4004e1: e8 a3 ff ff ff callq 400489 4004e6: b8 00 00 00 00 mov $0x0,%eax 4004eb: 5b pop %rbx 4004ec: c9 leaveq 4004ed: c3 retq 4004ee: 90 nop 4004ef: 90 nop Disassembly of section .data: 00000000006008c0 <__data_start>: 6008c0: 00 00 add %al,(%rax) ... 00000000006008c4 : 6008c4: 5a pop %rdx 6008c5: 00 00 add %al,(%rax) ... 00000000006008c8 : 6008c8: 01 00 add %eax,(%rax) ... 00000000006008cc : 6008cc: 02 00 add (%rax),%al ... 00000000006008d0 : 6008d0: 03 00 add (%rax),%eax ... 00000000006008d4 : 6008d4: 04 00 add $0x0,%al ...

如果读者还记得2.2.3节中,关于GCC基于X64体系结构的调用约定的话,那就很容易可以看出,函数p1和p2都使用寄存器传递参数,顺序就是RDI, RSI, RDX, RCX,这些细节已经跟regparm的规定完全不一致了。所以,在这里作者觉得,regparm已经不起作用了。

来源:https://my.oschina.net/LinuxDaxingxing/blog/751319
责任编辑:haq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144556
  • GNU
    GNU
    +关注

    关注

    0

    文章

    144

    浏览量

    18220

原文标题:你知道GNU C对C语言的扩展吗?

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    单片机开发功能安全编译器

    ”的代码路径。高级语言,特别是CC ++,包含数量众多的功能,这些功能的行为不是代码所遵循的语言规范所规定的。这种不确定的行为可能导致意外
    发表于 12-01 06:44

    哪些场合会用到volatile关键字?

    当你理解 volatile关键字的含义之后,你就能明白,其实很多场合都能用到 volatile关键字。 1.全局变量单片机开发,难免会用到全局变量。一些初级工程师,更是全局变量满天飞。这种情况下
    发表于 11-25 08:19

    C语言特性

    1、高效性:直接操作硬件 C 语言代码的执行效率极高,这是其最为显著的优势之一。它能够直接访问硬件资源,与底层硬件进行紧密交互,充分发挥硬件的性能潜力。在嵌入式开发,硬件资源往往十分
    发表于 11-24 07:01

    C语言在嵌入式开发的应用

    1、控制系统开发 在工业控制领域,C 语言是当之无愧的中流砥柱。无论是工业自动化生产线的运动控制、温度控制、压力控制等系统,还是汽车电子
    发表于 11-21 08:09

    哪些电子产品会用到贴片Y电容?

    贴片Y电容,又称为表面贴装Y电容,外观通常为扁平的矩形,是一种特殊的电容器类型。由于其独特的性能优势用于许多电子产品。哪些电子产品会用到贴片Y电容呢?
    的头像 发表于 11-13 11:05 237次阅读
    哪些电子产品<b class='flag-5'>会用到</b>贴片Y电容?

    【HZ-T536开发板免费体验】2 - 交叉编译仓颉编程语言程序到开发板运行

    AARCH64的编译器(我使用的是WSL2): sudo apt install gcc-aarch64-linux-gnu 然后需要拷贝aarch64开发以下三个目录的文件到x86_64的Linux软件包
    发表于 07-16 21:27

    工业物联网网关会用到哪些电子模组

    工业物联网网关通常会用到通信模组、主控模组、安全模组、接口扩展模组和电源管理模组等,以下是具体介绍: 通信模组:用于实现网关与外部网络或设备的通信连接。常见的有5G/4G模组,如华为MH5000、移
    的头像 发表于 07-11 17:56 720次阅读

    工业RTU会用到哪些芯片

    工业RTU(远程终端单元)通常会用到处理器芯片、通信芯片、数据采集芯片、存储芯片和电源管理芯片等。
    的头像 发表于 07-05 09:15 558次阅读

    工业网关会用到哪些芯片

    工业网关通常会集成多种芯片以满足其复杂的功能需求,具体可能会用到以下几类芯片: 处理器芯片:这是工业网关的核心部件,负责执行控制指令、数据处理以及运行操作系统等任务。可能会采用高性能的ARM架构
    的头像 发表于 07-03 17:26 518次阅读

    提高篇——C语言核心技术(中文版)

    严谨的术语表介绍C语言;第二部分描述标准链接库;第三部分介绍GNU软件包中常用的编译和测试工具。 获取完整文档资料可下载附件哦!!!!如果内容有帮助可以关注、点赞、评论支持一下哦~
    发表于 06-13 16:39

    HTTP协议在工业领域会用到

    HTTP协议在工业领域会用到,并且在工业互联网、设备管理、数据交互等多个方面发挥着重要作用,以下为你详细介绍: 工业互联网场景 设备接入与管理 原理:在工业互联网平台中,各类工业设备(如传感器
    的头像 发表于 06-03 09:17 513次阅读

    深入理解C语言C语言循环控制

    C语言编程,循环结构是至关重要的,它可以让程序重复执行特定的代码块,从而提高编程效率。然而,为了避免程序进入无限循环,C语言提供了多种循
    的头像 发表于 04-29 18:49 1728次阅读
    深入理解<b class='flag-5'>C</b><b class='flag-5'>语言</b>:<b class='flag-5'>C</b><b class='flag-5'>语言</b>循环控制

    S32G2如何利用C语言开发IPCF?

    S32G2 应该如何利用 C语言在 A 核上开发 IPCF 程序,是否有相关的 SDK 可用?或者我需要将 ipc-shm 等封装到一个 C
    发表于 03-27 06:49

    分析C语言代码结构的设计问题

    来分析一个C语言代码结构的设计问题。 这段代码,使用了两次malloc,分别给 p1 和 p2 申请了内存。用完后,内存释放,防止内存泄漏。 大家觉得,这样的代码设计有没有问题。 代码是某位学员在
    的头像 发表于 02-11 09:31 658次阅读

    语言模型开发框架是什么

    语言模型开发框架是指用于训练、推理和部署大型语言模型的软件工具和库。下面,AI部落小编为您介绍大语言模型开发框架。
    的头像 发表于 12-06 10:28 820次阅读