GNU C 扩展(二)

Keil5中开启GNU扩展的3个隐藏技巧(附配置截图) 本文详细介绍了在Keil5中开启GNU扩展的3个隐藏技巧,包括特定版本兼容性设置、混合编译参数优化和避免配置冲突的实用方法。通过配置截图和实战案例,帮助开发者充分利用GNU工具链提升开发效率和代码兼容性,特别适合C/C++嵌入式开发人员。 阅读详情

七、attribute机制
在GNU C中, 允许声明函数、变量和类型的特殊属性,以便指示编译器进行特定方面的优化和更仔细的代码检查。使用方式为在声明后面加上: __attribute__(( ATTRIBUTE ))。关键字__attribute__用来在声明的时候指定一个特定的属性。该关键字后面紧跟两对圆括号,括号里指定具体的属性,多个说明之间以逗号分隔。

GCC支持很多属性,常用的有以下这些:

1、noreturn
该属性用于函数,表示该函数从不返回。它能够让编译器生成较为优化的代码,消除不必要的警告。例如:

int for_testing(int);
void myexit(void) __attribute__ ((noreturn));
int main(void)
{
    int i = 1;
    for_testing(i);
    return 0;
}
int for_testing(int n)
{
    if(n > 0)
        myexit( );
    else
        return 100;
}
void myexit(void)
{
    exit(0);
}

在这个例子中,如果函数myexit不用 __attribute__ ((noreturn))修饰的话,编译的时候会有警告信息,因为函数for_testing是又返回类型的,但是如果进到了if分支语句的话,就有可能执行exit函数而再也不返回了。
标准C库函数中有很多函数用到了这个属性,比如最熟悉的有exit() 和 abort(),这两个函数从来不返回。
extern void exit(int)   __attribute__((noreturn));
extern void abort(void) __attribute__((noreturn));


2、format
其格式是:format (archetype, string-index, first-to-check)。
属性format用于函数,表示该函数使用printf、scanf、strftime或者strfmon风格的参数,并可以让编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。
archetype指定哪种风格(printf,scanf,strftime,gnu_printf,gnu_scanf,gnu_strftime或者strfmon。你也可以用 __printf__,__scanf__,__strftime__ 或者__strfmon__),string-index指定传入函数的第几个参数是格式化字符串,first-to-check指定从函数的第几个参数开始是变参。
比如:
    static inline int printk(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
这是include/kernel.h中对printk()函数的声明,其中printk的第1个参数是格式化字符串,从第2个参数开始根据格式化字符串检查变参。


3、unused
属性unused用于函数和变量,表示该函数或者变量可能并不使用,这个属性能够避免编译器产生警告信息。比如:
int maybe __attribute__((unused));

void __attribute__((unused)) maybe(void)
{
    printf("whatever");
}

4、section("section-name")
通常,编译器会把生成的代码放在 .text 代码段中,但是有时候你可能需要一些额外的段,或者你需要把你的函数放在特定的段中。属性section允许你的这些要求。例如:
    extern void foobar (void)__attribute__((section("bar")));
编译器将会把函数foobar放在bar这个段里面。

再比如:
++++ include/linux/init.h
#define  __init  __attribute__((section(".init.text")))
#define  __initdata  __attribute__((section(".init.data")))
#define  __exitdata  __attribute__((section(".exit.data")))
#define  __exit_call  __attribute_used__ __attribute__((section(".exitcall.exit")))
通常编译器将函数放在.text段中,静态变量放在.data或者.bss段里面,而使用section属性,可以让编译器将函数或变量放在指定的段中。因此上面对 __init 的定义便表示将 __init 修饰的代码放在 .init.text 段里面。(放在init段里面的代码只会在初始化的时候被执行一遍,因此该段的代码可以在执行之后释放)。


5、aligned(ALIGNMENT)
属性aligned用于变量、结构或者联合,设定一个指定大小的对齐格式,以字节为单位。但是要注意,这个属性的设定只能用来增加对齐地址而不能减少,例如:
char c __attribute__((aligned(16))); //让变量 c 以16字节对齐。
int i __attribute__((aligned(2))); //该aligned属性想要设定变量 i 以2字节对齐,但由于 i 需要4字节对齐。因此该声明无效。
再如:
struct ohci_hcca
{
#define NUM_INTS 32
    __hc32 ini_table [NUM_INTS];

    __hc32 frame_no;
    __hc32 done_head;
u8 reserved_for_hc [116];
u8 what[4];
} __attribute__((aligned(256)));
这表示结构体 ohci_hcca 以256字节对齐。

对于结构体的大小而言,网上书上都有一些比较含糊其辞的解释,今天我再啰嗦两句,彻底解决这个问题。一个结构体的大小取决于里面的成员的排列顺序,以及需要最大对齐方式的那个成员。怎么理解呢? 请看下面这几个例子:
struct A
{
    short s1, s2;
    char c;
};


sizeof(struct A) = 6。因为A成员中最大的对齐成员是short类型,2字节对齐,因此成员c后面需要补1个零。因此总共占用6个字节。

struct B
{
    int i;
    char c;
};

 

sizeof(struct B) = 8。因为B成员中最大的对齐成员是int类型,4字节对齐,因此成员c后面需要补3个零。因此总共占用8个字节。

struct C
{
    double lf;
    char c;
};


sizeof(struct C) = 12。因为C成员中最大的对齐成员是double类型,4字节对齐,因此成员c后面需要补3个零。因此总共占用8个字节。这里一定要注意,一个变量的最小地址对齐格式跟它所占的字节大小不要混淆,一个变量所占的字节的大小指的是变量的尺寸大小,而一个变量的最小地址对齐格式,指的是一个变量的起始地址的值至少是某个数的整数倍,比如int型的最小对齐格式是4个字节,因此int型变量的起始地址至少是4的倍数(可以是8的倍数,16的倍数等)。

再澄清一下,一个结构体里面有很多成员,每个成员都有自己的“最小对齐格式”,那么对于整个结构体来说呢?它的“最小对齐格式”又是什么呢?那就取决于成员中最大的那个“最小对齐格式”,这样说明白了吗? 再来看一个复杂点的例子:

struct D{
    int i;
    char c __attribute__((aligned(256)));
    short s;
};


这时,sizeof (struct D) = 512。由于结构体D中包含的成员c被aligned属性限定为最小256字节对齐,因此整个结构体也要256字节对齐,因此 i 的起始地址a是一个256的倍数,另外,成员c的起始地址也必须是256的倍数,因此 i 与 c 之间空了很多零,另外s两字节对齐,之后统统补零,因为要256对齐,整个结构体占512字节。
如果我们变换一下成员的相对位置,则就不一样了:
struct E
{
    char c __attribute__((aligned(256)));
    int i;
    short s;};

同样的,地址a和地址b都是256的地址,因为虽然成员 c 只占一个字节,但是它的最小对其格式是要256字节对齐,这也决定了整个结构体的最小对齐格式,因此s之后一直补零,一直补满256个字节。


6、packed属性packed用于变量和类型,当用于修饰变量(包括结构体成员)时表示使用最小可能的地址对齐格式(如果此时该变量被aligned属性所修饰,那么它的最小地址对齐格式就是aligned所指定的那个值),当用于修饰枚举、结构体或者联合类型时表示使该类型内的所有成员都具有可能的最小的地址对齐格式(就相当于一次性修饰每一个成员)。
例如:
struct A
{
    char c;
    int i __attribute__((packed));
    short s;
};


被packed修饰的变量 i 会以1个字节对齐,因此整个结构体占8个字节。(否则占12字节)

struct B
{
    char c;
    int i;
    short s;
}__attribute__((packed));
被packed修饰的结构体B会让它里面的所有的成员都具有尽可能小的地址对齐格式,因此整个结构体将会占用 1+4+2 = 7 个字节。

struct C
{
    int i __attribute__((aligned(256)));
    char c;
    short s;
}__attribute__((packed));
被packed修饰的结构体C同样会让它里面的所有的成员都具有尽可能小的地址对齐格式(记住!这代表 i 的起始地址至少是256 的倍数,但是别忘了它只占4个字节,c成员被放置在 i 之后的第4个字节处),但如果结构体C没有packed修饰,成员s的地址将会是偶数,但是有packed修饰的这个结构体中,s的地址将会是紧邻c之后的奇数.

nRF52开发笔记:解决Keil中anonymous structs的编译限制 本文详细解析了在nRF52开发中使用Keil编译时遇到的anonymous structs报错问题,提供了两种有效解决方案:使用#pragma预处理指令和启用--gnu mode。文章还深入探讨了编译器原理差异,并分享了实际项目中的最佳实践,帮助开发者高效解决跨平台编译兼容性问题。 阅读详情

相关推荐

C语言标准,ANSI C,ISO C,GNU C

丹尼斯·里奇(Dennis Ritchie)于1969年在 AT&T 贝尔实验室编写Unix 操作系统,实现该系统的程序语言就是C语言,因此里奇是C语言之父与UNIX之父,后面的Linux、Window、MAC OS都是基于UNIX进行开发的。 1、 K&R C标准 1978年,布莱恩·柯林汉(Brian Kernighan)和丹尼斯·里奇(Dennis Ritchie)出版了《The C Programming Language》这本书,作为C语言的非正式标准,称为K&a.

goodshanzi的博客 7487

c语言的数据类型中复合类型的代码,复合数据类型

咱们知道,C语言中有许多基本数据类型,比如int型,float型,double型等,我们经常使用这些基本数据类型来表达一些简单的数据,比如一个人的年龄可以用 int 型数据来表示,一本书的价格可以用 float 型数据来表示等等。但另一方面,在我们的日常生活中遇到更多的数据是复合的数据类型,比如一个学生,或者一本书。一个学生包含很多元素:姓名、性别、年龄、电话、住址等等,一本书也包含很多信息:价格...

weixin_32338107的博客 524

SAP WMS开发实战:用BAPI_L_TO_CREATE_MULTIPLE搞定LT01转储单(附完整代码)

本文详细解析了SAP WMS开发中如何利用BAPI_L_TO_CREATE_MULTIPLE函数模块批量创建LT01转储单。文章深入剖析了核心参数、常见错误及实战代码框架,重点强调了源/目标存储类型等关键字段的获取方法,为系统集成与自动化流程开发提供了可靠的解决方案。

view3的博客 561

4 __attribute__((aligned))说明

摘要: attribute__是GNUC特有的语法机制,用于设置函数、变量和类型的属性。其语法格式为__attribute((attribute-list))。作为修饰符时,适用于对象(类似const等类型限定符)、函数(类似inline等说明符)或结构体/联合体/枚举(需置于类型标识符前)。常用的aligned属性可指定函数首地址的最小对齐字节数。__attribute__机制扩展了C语言的语法功能,是GNUC的重要特色之一。(98字)

u012906122的专栏 2537

Origin科研绘图——桑基图

是一种用于展示“流动”(flow)关系的可视化图表,常用于呈现能量流、物质流、资金流、信息流等在不同节点之间的传递和分配情况。它最大的特点是用“宽度可变的流线”来直观表示数量大小——流线越宽,代表流量越大,因此特别适合理解复杂系统中资源从哪里来、到哪里去、以及不同路径所占比例。为该流程对应的数量。只需将各个流程逐项填写在 A、B、C 三列即可,流程的排列顺序并非关键,确保起点、终点及对应数值准确才是最重要的。与柱状图、饼图不同,桑基图不仅展示“多少”,还展示“从哪到哪”。至此,本期教程就结束啦。

weixin_41301530的博客 1394

SAP Script表单开发中ABAP preform方法的实战应用与调试技巧

本文深入探讨了在SAP Script表单开发中调用ABAP程序(preform方法)的实战应用与调试技巧。通过一个获取供应商版本名称的实例,详细讲解了如何在SE71中嵌入PERFORM指令、编写ABAP子程序进行数据查询与处理,并重点介绍了使用SAP Script Debugger进行高效调试的方法,帮助开发者灵活扩展表单功能,实现复杂业务逻辑。

o0p1q2r3的博客 551

__attribute__((__aligned__(n)))对结构体对齐的影响

1. __attribute__ 是什么? __attribute__是GCC里的编译参数,用法有很多种,感兴趣可以阅读一下gcc的相关文档。这里说一下__attribute__对变量和结构体对齐的影响。这里的影响大概分为两个方面,对齐和本身占用的字节数的大小,即sizeof(变量)的值。 2. __attribute__((__aligned__(n)))对变量的影响 使用的语法如下: int ...

less is more 1万+

详述字符集与汉字编码

字符集与字符编码是文本处理的基础概念。字符集定义字符集合(如ASCII、GB2312、Unicode),字符编码则规定字符如何存储为二进制数据。汉字编码经历了从区域化(GB2312、GBK、BIG5)到全球化(Unicode)的演进,Unicode通过UTF-8、UTF-16等编码方案实现跨语言兼容。UTF-8因兼容ASCII、节省空间且无乱码风险,成为中文互联网的主流编码。正确处理编码问题需统一标准、明确声明格式,并注意生僻字的特殊处理。

零零发不爱ai的博客 805

C __attribute__编译属性整理

最近在看VPP源码,很多变量、函数都设置了编译属性,编译属性的作用却不是很明确,为了增加记忆以及方便日后查阅,在此整理并分享给大家。

mrtyxr的博客 1057

基于STM32、HAL库的WF162A 11BA T&R气压传感器 驱动程序设计

/ 转换为7位地址。* @param temperature: 存储读取到的温度值(°C)* @param temperature: 存储读取到的温度值(°C)* @param pressure: 存储读取到的压力值(bar)* @param pressure: 存储读取到的压力值(bar)* @param range: 压力范围(bar)

corlin6688的博客 363

OpenCV实例(八)车牌字符识别技术(三)汉字识别

相较于数字和英文字符的识别,汽车牌照中的汉字字符识别的难度更大,主要原因有以下4个方面:(1)字符笔画因切分误差导致非笔画或笔画流失。(2)汽车牌照被污染导致字符上出现污垢。(3)采集所得车辆图像分辨率低导致多笔画的汉字较难分辨。(4)车辆图像采集时所受光照影响的差异导致笔画较淡。综合汉字识别时的这些难点来看,很难被直接提取的是字符的局部特征。笔画作为最重要的特征而仅存在于汉字中,这由先验知识可知。一旦捺、横、竖、撇这些笔画特征被提取到,对于汉字字符识别的工作就完成了许多。

小幽余生不加糖 1650

GNU C对ISO标准的扩展——笔记(二)

Arrays of Variable Length变长数组,ISO C99标准中正式支持,在C89模式下作为GCC的扩展特性。变长数组即数组长度为变量,除此之外与普通数组在声明语法上没有区别。变长数组在声明处分配空间(在栈上分配空间而不是在堆上,这一点与函数alloca/_alloca相同,实际上用gdb调试发现,变长数组的空间分配就是通过调用alloca完成的),在作用域结束时自动收

jcwKyl的专栏 2696

【虚幻引擎UE】UE5 可编辑动态样条线轨迹及AI跟随路径移动(含工程源码)

【虚幻引擎UE】可编辑动态样条线轨迹及AI跟随路径移动

灵境引路人 6227

GNU C语言的 扩展(二)零长度数组&可变参数宏

GNU C 允许使用零长度数组,在定义变长的头结构时,这个特性非常有用。 测试代码: 引用 #include #include #include typedef structuser_def {         char *name;         int  length;         char bytes[0]; } user_de

堂吉诃德的专栏 806

YOLOV8改进:添加Wiseiou,有效涨点

【代码】YOLOV8改进:添加Wiseiou,有效涨点。

AIcurator的博客 2391

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

解决Vscode中使用netdb.h的getaddrinfo和addrinfo会报错的方法

博主最近在学习c语言的socket编程,在调用netdb.h中的相关函数和变量api时,遇到了一些问题,因此本文将给出解决的方法,并且进行分析在代码文件中添加的宏定义或者在.vscode中新建一个,然后在这个文件中定义这个宏,我个人推荐这个做法,因为修改配置文件能作用于整个工程,上面那种只能作用于单个文件。],],现在来分析一下为什么会报错,造成报错的原因是什么。然后总结一下。

m0_73366745的博客 1240

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C预处理器-25( 吞掉分号的问题、副作用的重复计算)

局部变量的名字后面带有下划线,以减少与更广泛作用域中的标识符发生冲突的风险(完全避免冲突是不可能的)。严格来说,这个调用会展开为一个复合语句,它是一个完整的语句,不需要用分号来结束。这里使用了反斜杠换行符来分割宏定义,尽管宏定义在逻辑上必须是一行,但这样可以让它看起来像是非宏代码的布局方式。之间存在两条语句——一条是复合语句,另一条是空语句——这会导致无效的 C 代码。通常,我们希望定义一个展开为复合语句的宏。有副作用,或者它的计算耗时较长,结果可能与预期不符。的值,将其保存在一个变量中,然后在。

snow_feeling的专栏 362

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

GNU C扩展

GNU C是在C89标准(ANSI  C 标准)的基础上的扩展,以下内容仅作为《GNU C用户手册》中,区别于C89标准的记录,以供自查。《GNU C 用户手册》参考网址: http://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Initializing-Pointers   1、标识符扩展 GUN C 中可以使用 美元字符“$...

1558009762的博客 2172

GNU C扩展语法归纳详解_gnu c 扩展

通过 format(printf,1,2) 属性声明,告诉编译器:LOG() 函数的参数,其格式字符串的位置在所有参数列表中的索引是 1,即第一个参数;这个函数定义多了一个参数 num,格式字符串在参数列表中的位置发生了变化(在所有的参数列表中,索引由1变成了2),要检查的第一个变参的位置也发生了变化(索引从原来的2变成了3)。根据结构体的对齐规则,结构体的整体对齐要按结构体所有成员中最大对齐字节数或其整数倍对齐,或者说结构体的整体长度要为其最大成员字节数的整数倍,如果不是整数倍则要补齐。

2401_86436837的博客 1500

嵌入式C语言自我修养:GNU C编译器扩展语法精讲

)(void)是一个类型转换,它将后面的表达式转换为void类型,这意味着表达式的结果被丢弃。而是一个比较两个变量地址是否相同的表达式,这个表达式的结果是一个布尔值,但通过将其转换为void类型,这个结果就被忽略了。void这一行代码的目的是让编译器认为_min1和_min2(或_max1和_max2)这两个变量被使用了,从而避免编译器发出未使用变量的警告。长度为0的数组int a[0];零长度数组有一个特点,就是不占用内存存储空间。

_ 2418

GNU C扩展语法

Linux上可用的C编译器是GNU C编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布。GNU C对标准C进行一系列扩展,以增强标准C的功能。keil中,已经包含了对GNU C的支持。 1.零长度和变量长度数组 GNU C允许使用零长度数组,在定义变长对象的头结构时,这个特性非常有用。例如: struct var_data { int len; char data[0]; } char data[0]仅仅意味着程序中通过var_data结构体实例的data[in

weixin_41579872的博客 951

GNU C对ISO标准的扩展——笔记(一)

在朋友的博客上看到这样的C语言初始化方式:int arr[10] = { [5] = 7 }; // a[5] = 7;以前没有用过也不知道有这样的写法。在网上找了一下这方面的资料,最后在http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc/C-Extensions.html找到了答案。以下所有内容都来自这个网址。上面的那行C语言初始化语法叫做Designat

jcwKyl的专栏 3714

c11语言编译器,GNU C编译器的gnu11和c11

国际标准组织发布c11后,gnu为自己的编译器发布两种标准gnu11和c11gnu11:带gnu c扩展的c11标准,如果你的代码包含了typeof,__attribute__等等gnu的扩展,就必须用这个。c11:这个就是纯c11的标准,不带gnu扩展。可以在Makefile中声明:CFLAGS=-std=gnu11 -g -Wall或者,纯标准的c11,玩linux的要慎用,因为linux代码...

weixin_36385884的博客 2219
上一篇: GNU C扩展(一)
下一篇: C语言中宏定义和函数的取舍
pointfish
博客等级 码龄17年 58粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值