当前位置:首页 > 单片机 > 单片机
[导读] 编译指示(Pragma Directives)可能是所有的预处理指令中最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对编译器给出了如何处理特定的函数、对象和代码段的方法,在保持与C

 编译指示(Pragma Directives)可能是所有的预处理指令中最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对编译器给出了如何处理特定的函数、对象和代码段的方法,在保持与C/C++语言完全兼容的情况下,给出主机(比如C28x)或操作系统(比如DSP/BIOS)专有的特征。这些编译指示的使用较为复杂,但是我们还必须要了解它们,因为它们是程序中必不可少的东西,例如#pragma DATA_SECTION ( symbol , " section name ");这样的。但是往往讲解它们的资料又不多(因为大部分资料集中在入门指南上面),所以在此我们就总结一下针对C28x编译器的pragma指令,再遇到它们的时候就不会一头雾水了。

1. CHECK_MISRA

它的作用与在编译器选项中使用--check_misra是相同的,都是对特定源文件使能MISRA-C:2004规则检查(汽车工业软件可靠性联会),使用方法是:

#pragma CHECK_MISRA (" {all|required|advisory|none|rulespec} ");

其中的rulespec是具体MISRA中的规则,使用方法请参考DSP编程技巧之12-揭开编译器神秘面纱之代码规范MISRA-C。

2. CLINK

CLINK指令可用于某段代码或者某个数据符号,使用之后会在包含被作用符号的段中产生一个.clink指示,表明在条件链接的情况下,如果这个段没有被其它任何段引用的话,这个段可以被移除,从而减小链接输出文件的尺寸。使用方法是:

#pragma CLINK (symbol )

3. CODE_ALIGN

CODE_ALIGN用来沿着特定的对齐参数constant来对齐函数(从而可以让CPU更快寻址,更快执行指令)。当我们希望函数从特定的边界开始的时候,这个指令非常有用。参数constant必须是2的幂(偶数对齐),使用方法是:

C代码: #pragma CODE_ALIGN ( func, constant );

C++代码: #pragma CODE_ALIGN ( constant );

注:在本文中,在C和C++代码中,指令使用方法一样时,不分别写出,如不一样则分C代码和C++代码分别写出。C代码中的#pragma指令一般需指定函数名,也即其作用域;C++代码中的#pragma指令一般不带有函数名,其作用域为紧邻该指令后面的函数;下同。

4. CODE_SECTION

CODE_SECTION是较为常见的指令,默认情况下,代码被存放在.text段中,使用此指令则用来指定并改变某段代码所分配的段,其使用方法是:

C代码: #pragma CODE_SECTION (symbol , "section name ")

C++代码: #pragma CODE_SECTION (" section name ")

例如:

char bufferA[80];

char bufferB[80];

#pragma CODE_SECTION(funcA, "codeA")

char funcA(int i);

char funcB(int i);

void main()

{

char c;

c = funcA(1);

c = funcB(2);

}

char funcA (int i)

{

return bufferA[i];

}

char funcB (int j)

{

return bufferB[j];

}

5. DATA_SECTION

DATA_SECTION可能是使用最多的pragma指令了,它用来定义存储某个符号所使用的段,使用方法是:

C代码: #pragma DATA_SECTION ( symbol , " section name ");

C++代码: #pragma DATA_SECTION (" section name ");

例如:

#pragma DATA_SECTION(bufferB, "my_sect")

char bufferA[512];

char bufferB[512];

6. 与诊断信息有关的Pragma

诊断信息一般包括:提醒,警告,错误和不提示等几个级别,使用与诊断信息有关的Pragma和使用相关的编译器选项的结果是一样的,其使用方法以及们的对应关系如下:

Pragma对应的编译器选项

有关诊断信息的含义,请参考DSP编程技巧之7---揭开编译器神秘面纱之预处理与诊断。

7. FAST_FUNC_CALL

使用这个指令,会在编译时调用快速汇编指令FFC,而不是传统的CALL指令来完成函数的跳转,其使用方法是:

#pragma FAST_FUNC_CALL ( func );

它的使用范围是受限的:仅限于调用返回LB *XAR7指令的汇编程序。例如:

;汇编程序

_add_long:

ADD ACC, *-SP[2]

LB *XAR7

//调用汇编的C程序

#pragma FAST_FUNC_CALL (add_long);

long add_long(long, long);

void foo()

{

long x, y;

x = 0xffff;

y = 0xff;

y = add_long(x, y);

}

除此之外,如果使用该指令,编译器会输出警告信息,并忽略其指示。

8. FUNC_EXT_CALLED

在我们启用程序级别的优化选项时(-O3),所有未直接或者简介被main函数调用的函数都将被优化掉,但是这些函数也有可能被我们定义的某些汇编代码使用到,所以使用FUNC_EXT_CALLED可以在编译时保留这些代码,其使用方法是:

C代码: #pragma FUNC_EXT_CALLED ( func );

C++代码: #pragma FUNC_EXT_CALLED;

9. FUNCTION_OPTIONS

使用这个选项可以在编译C/C++代码中的某些函数时,使用额外的编译器的命令行选项,实现与在命令行中输入相关的命令同样的效果。其使用方法是:

C代码: #pragma FUNCTION_OPTIONS ( func, "additional options" );

C++代码: #pragma FUNCTION_OPTIONS( "additional options" );

10. INTERRUPT

使用这个选项可以在C代码中直接操作中断,其使用方法是:

C代码: #pragma INTERRUPT ( func );

C++代码: #pragma INTERRUPT ;

被该指令直接操作的函数将使用IRP(中断返回指针)来返回值。

在使用FPU时,中断分为两种:高优先级中断HPI和低优先级中断LPI,其中HPI使用快速的上下文存储机制,不能被嵌套,LPI则与普通的C28x中断机制一样,并且可以被嵌套。此时可以增加第二个参数来控制:

C代码: #pragma INTERRUPT ( func , {HPI|LPI} );

C++代码: #pragma INTERRUPT ( {HPI|LPI} );

在DSP/BIOS和SYS/BIOS HWI对象中,不能使用INTERRUPT指令,因为Hwi_enter/Hwi_exit宏和Hwi解包器已经包含了该函数,此时使用该指令会产生负面的效果。

11. MUST_ITERATE

使用这个指令的情况下,我们确信某个for循环能够执行指定的次数。使用这个指令能够帮助编译器确定循环的次数和最佳的实现方式,从而减小代码的尺寸。其使用方法是:

#pragma MUST_ITERATE ( min, max, multiple );

min是循环的最小次数,max是最大执行次数,multiple则是循环次数的整数倍,如果这其中某个参数不存在,则可以省略,例如:

#pragma MUST_ITERATE(5); /* 最少循环5次 */

#pragma MUST_ITERATE(5, , 5); /* max参数省略;循环次数是5的倍数次(至少1倍) */

pragma MUST_ITERATE(8, 48, 8);

/* 循环此时可能为8, 16, 24, 32, 40, 48 */

12. NO_HOOKS

该指令阻止在调用函数时自动产生进入钩子和退出钩子,使用方法是:

C代码: #pragma NO_HOOKS ( func );

C++代码: #pragma NO_HOOKS;

13. RESET_MISRA

顾名思义,这个指令会把MISRA-C:2004规则检查恢复到它原先的设定状态。例如,某条规则在命令行里被使能,但是在某段代码中被屏蔽了(某些原因导致它无法通过规则检查),使用该指令会规则检查重新使能。使用方法是:

#pragma RESET_MISRA (" {all|required|advisory|rulespec} ")

14. RETAIN

使用这个指令,可以避免某些符号在条件链接时被优化掉,从而在输出文件中保留它。使用方法是:

#pragma RETAIN ( symbol )

这个指令与我们的第二条,CLINK的效果是整好相反的。

15. SET_CODE_SECTION与SET_DATA_SECTION

这两条指令用来设置其后所有声明的段。使用方法是:

C代码: #pragma SET_CODE_SECTION ("section name")

C++代码: #pragma SET_DATA_SECTION ("section name")

例如:

#pragma SET_DATA_SECTION("mydata")

int x;

int y;

#pragma SET_DATA_SECTION()

其中的x和y都被会放入我们指定的段mydata中,直到我们使用空参数SET_DATA_SECTION(),之后的代码或数据才会被放入默认的段之中。

16. UNROLL

UNROLL是“摊开”的意思,这个指令与for/while相关,意思是把n次的循环给展开,从而有个n份同样的代码。循环展开,是一种牺牲程序的尺寸来加快程序的执行速度的优化方法。可以手动编程完成,也可由编译器自动优化完成。循环展开通过将循环体代码复制多次实现。循环展开能够增大指令调度的空间,减少循环分支指令的开销。循环展开可以更好地实现数据预取技术。其使用方法是:

#pragma UNROLL( n );

只有在编译器认为n是安全的(即展开之后确实都能执行),才能执行此操作。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭