MPLAB C30 与ANSI C 的差别(一)关键字的区别
2.1 简介本章讨论MPLAB C30 语法支持的C 语言和1989 年标准ANSI C 之间的差别。
2.2 主要内容
本章包括以下主要内容:
· 关键字差别
· 语句差别
·表达式差别
2.3 关键字差别
本节说明ANSI C 和MPLAB C30 所接受C 在关键字方面的差别。新关键字是基本
GCC 实现的一部分,本节的讨论基于标准的GCC 文档,选择GCC MPLAB C30 部分
的特定语法和语义来讲述。
· 指定变量的属性
·指定函数的属性
· 内联函数
· 指定寄存器中的变量
· 复数
· 双字整型
· 用typeof 引用类型
2.3.1 指定变量的属性
MPLAB C30 的关键字__attribute__ 用来指定变量或结构位域的特殊属性。关键
字后的双括弧中的内容是属性说明。下面是目前支持的变量属性:
· address (addr)
·aligned (alignment)
· deprecated
· far
· mode (mode)
· near
· noload
· packed
· persistent
· reverse (alignment)
·section ("section-name")
· sfr (address)
· space (space)
· transparent_union
· unordered
· unused
· weak
也可以通过在关键字前后使用__ (双下划线)来指定属性(例如,用__aligned
__ 代替aligned)。这样将使您在头文件中使用它们时不必考虑会出现与宏同名的情
况。
要指定多个属性,可在双括弧内用逗号将属性分隔开,例如:
__attribute__ ((aligned (16), packed)
address (addr)
address 属性为变量指定绝对地址。这个属性不能与section 属性同时使用;
address 属性优先。带address 属性的变量不能存放到_psv 空间(参见space() 属
性或-mconst-in-code 选项);这样做会产生警告,且编译器将此变量存放到psv
空间。
如果要将变量存放到PSV 段,地址应为程序存储器地址。
int var __attribute__ ((address(0x800)));
aligned (alignment)
该属性为变量指定最小的对齐方式,用字节表示。对齐方式必须是2 的次幂。例如,
下面的声明:
int x __attribute__ ((aligned (16))) = 0;
使编译器按照16 字节分配全局变量x。对于dsPIC 器件,这可以与访问需要对齐的
操作数的DSP 指令和寻址模式的asm 语句配合使用。
在前面的例子中,我们可以显式地指定我们希望编译器对给定变量使用的对齐方式
(用字节表示)。或者,我们可以省略对齐方式,而要求编译器为变量使用dsPIC 器件
的最大有用对齐。例如,我们可以这样写:
short array __attribute__ ((aligned));
当省略了对齐属性说明中的对齐方式时,编译器会自动将已声明变量的对齐方式设置
为目标单片机任何数据类型所使用的最大对齐方式。在dsPIC 器件中,为双字节(1
个字)。
aligned 属性只能增大对齐;但可以通过指定packed 属性来减小对齐(见下文)。
aligned 属性与reverse 属性冲突,同时指定两者会产生错误。
deprecated
deprecated 属性使得包含这一属性的声明能被编译器特别识别到。当使用
deprecated 函数或变量时,编译器会发出警告。
deprecated 定义仍将被编译器执行,并被反映到目标文件中。例如,编译以下程序:
int __attribute__((__deprecated__)) i;
int main() {
return i;
}
将产生警告:
deprecated.c:4: warning: `i' is deprecated (declared
at deprecated.c:1)
在生成的目标文件中,仍以通常的方式定义了i。
far
far 属性告知编译器不必将变量分配到near(前8 KB)数据空间中(即变量可以分配
到数据存储器中的任何地址)。
mode (mode)
在变量声明中使用该属性来指定与模式mode 对应的数据类型。实际上就是允许根据
变量的宽度指定整数或浮点数类型。mode 的有效值见下表:
模式宽度MPLAB C30类型 QI
8 位 char HI 16 位 int
SI 32 位 long DI 64 位 long long SF 32 位 float DF 64 位 long double
这一属性对于编写可在所有MPLAB C30 支持的目标单片机之间移植的代码很有用。
例如,如下函数将两个32 位有符号整数相加,并返回一个32 位有符号整数结果:
typedef int __attribute__((__mode__(SI))) int32;
int32
add32(int32 a, int32 b)
{
return(a+b);
}
可以指定 byte 或__byte__ 模式指明模式对应于单字节整数, word 或__word__
模式对应于单字整数, pointer 或__pointer__ 模式用于表示指针。
near
near 属性告知编译器将变量分配到near 数据空间(数据存储器的前8 KB)。对这种变
量的存取有时比存取未分配(或不知已分配)到near 数据空间的变量效率高。
int num __attribute__ ((near));
noload
noload 属性指明应该为变量分配空间,但不应为变量装入初值。这一属性对于设计在
运行时将变量装入存储器(如从串行EEPROM)的应用程序会有用。
int table1 __attribute__ ((noload)) = { 0 };
packed
packed 属性指定变量或结构位域采用最小的可能对齐方式 —— 变量占一个字节,位
域占一位,除非用aligned 属性指定了一个更大的值。
下面的结构中位域x 被压缩,所以它紧接在a 之后:
struct foo
{
char a;
int x __attribute__ ((packed));
};
注: dsPIC 器件要求字按偶数字节对齐,因此在使用packed 属性时要特别
小心,避免运行时寻址错误。
persistent
persistent 属性指定在启动时变量不应被初始化或清零。具有persistent 属性的
变量可用于存储器件复位后仍保持有效的状态信息。
int last_mode __attribute__ ((persistent));
reverse (alignment)
reverse 属性为变量的结束地址加1 指定最小对齐。对齐以字节指定,必须是2 的次
幂。反向对齐的变量可用于递减dsPIC 汇编语言中的模缓冲区。如果应用程序需要在
C 中定义的变量可从汇编语言访问,这一属性会有用。
int buf1 __attribute__ ((reverse(256)));
reverse属性与aligned和section属性冲突。试图为反向对齐的变量指定一个段将
被忽略,并发出警告。为同一个变量同时指定reverse 和aligned 会产生错误。带
有reverse 属性的变量不能存放到auto_psv 空间(参见space 属性或
-mconst-in-code 选项);试图这样做将导致警告,且编译器会将变量存放到psv 空
间。
section ("section-name")
默认情况下,编译器将其生成的目标代码存放在.data 和.bss 段中。section 属
性允许指定变量(或函数)存放到特定的段中。
struct array {int i;}
struct array buf __attribute__ ((section("userdata"))) = {0};
section 属性与address 和reverse 属性冲突。在这两种冲突情形下,段名将被忽
略,并发出警告。这一属性还可能与space 属性冲突。更多信息,参见关于space
属性的说明。
sfr (address)
sfr 属性告知编译器变量将变量分配到near 数据空间(数据存储器的前8 KB),同时
使用address 参数指定变量的运行时地址。对这种变量的存取有时比存取未分配
(或不知已分配)到near 数据空间的变量效率高。
extern volatile int __attribute__ ((sfr(0x200)))u1mod;
为避免产生错误,需要使用extern 说明符。
space (space)
一般来说,编译器在一般数据空间内分配变量。可使用space 属性来指示编译器将变
量分配到特定存储空间。关于存储空间的更多论述参见第4.6 节“存储空间”。
space 属性接受如下参数:
data
将变量分配到一般数据空间。可使用普通C 语句访问一般数据空间中的变量。
这是默认的分配。
xmemory
将变量分配到X 数据空间。 可使用普通C 语句访问 X 数据空间中的变量。
xmemory 空间分配举例如下:
int x __attribute__ ((space(xmemory)));
ymemory
将变量分配到Y 数据空间。 可使用普通C 语句访问 Y 数据空间中的变量。
ymemory 空间分配举例如下:
int y __attribute__ ((space(ymemory))); prog
将变量分配到程序空间中为可执行代码指定的段。程序空间中的变量不能使用普
通C 语句访问,这些变量必须由编程人员显式访问,通常通过表访问行内汇编
指令,或使用程序空间可视性窗口访问。
auto_psv
将变量分配到程序空间中为自动程序空间可视性(PSV)窗口访问指定的编译
器管理段。auto_psv 空间中的变量可使用普通C 语句来读(但不能写),且变
量的分配空间最大为32K 。当指定space(auto_psv) 时,不能使用。
section 属性指定段名;任何段名将被忽略并产生警告。auto_psv 空间中的变
量不能存放到特定地址或反对齐。
注: 在启动时分配到auto_psv 段中的变量不装载到数据存储器。这一属
性对于减少RAM 使用可能有用。
psv
将变量分配到程序空间中为程序空间可视性(PSV)窗口访问指定的段。链接
器将定位段,因此可以通过PSVPAG 寄存器的设置来访问整个变量。PSV 空间
中的变量不是由编译器管理的,不能使用普通C 语句访问。这些变量必须由编
程人员显式访问,通常使用表访问行内汇编指令,或使用程序空间可视性窗口访
问。
eedata
将变量分配到EEData 空间。EEData 空间中的变量不能使用普通C 语句访问。
这些变量必须由编程人员显式访问,通常使用表访问行内汇编指令,或使用程序
空间可视性窗口访问。
transparent_union
这是属于union 型函数参数的属性,即相应的参数可以是任何联合成员的类型,但以
第一个联合成员的类型传递参数。使用 transparent 联合的第一个成员的调用约定将参
数传递给函数,而不是使用联合本身的调用约定。联合的所有成员必须具有相同的机
器码表示,这对于保证参数传递正常进行是必需的。
unordered
unordered 属性表明变量存放的地址可以相对于所在C 源文件中其他变量的位置而改
变。这不符合ANSI C,但可使链接器更好地利用存储空隙。
const int __attribute__ ((unordered)) i;
unused
这一变量属性表明变量可能不被使用。MPLAB C30 不会为这种变量产生未使用变量
警告。
weak
weak 属性声明weak 符号。weak 符号可能被全局定义取代。当对外部符号的引用使用
weak 时,则链接时不需要该符号。例如:
extern int __attribute__((__weak__)) s;
int foo() {
if (&s) return s;
return 0; /* possibly some other value */
}
在上面的程序中,如果s 没有被其他模块定义,程序仍会链接,但不会给s 分配地
址。若条件验证s 已被定义,就返回它的值(如果它有值的话)。否则将返回“0”
值。这个特征很有用,主要用于提供与任意库链接的通用代码。
weak 属性可以应用于函数和变量:
extern int __attribute__((__weak__))
compress_data(void *buf);
int process(void *buf) {
if (compress_data) {
if (compress_data(buf) == -1) /* error */
}
/* process buf */
}
在上述代码中,函数compress_data 只有在与其他模块链接时才使用。是否使用该
特性是由链接时决定的,而不是由编译时决定的。
weak 属性对定义的影响更为复杂,需要多个文件加以说明:
/* weak1.c */
int __attribute__((__weak__)) i;
void foo() {
i = 1;
}
/* weak2.c */
int i;
extern void foo(void);
void bar() {
i = 2;
}
main() {
foo();
bar();
}
在weak2.c 中对i 的定义使符号成为强定义。链接时不会出现错误,两个i 指向同
一个存储位置。为weak1.c 中的i 分配存储空间,但这个空间不可访问。
不能保证两个程序里的i 具有相同的类型,如果将weak2.c 中的i 改为float 型,
仍然允许链接,但是函数foo 的操作将无法预料。foo 将向32 位浮点值的最低有效
部分写入一个值。相反,在weak1.c 中把i 的weak 定义改为float 型,将导致灾
难性结果。这样会把一个32 位的浮点值写到16 位的整型地址中,覆盖掉紧接i 之后
存储的任何变量。
在只存在weak 定义的情况下,链接器才选择为第一个这种定义分配存储空间。其他
定义是不可访问的。
无论符号属于什么类型,操作是相同的;函数和变量具有相同的操作。
页:
[1]