加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 14.8  变量类型
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

高效的C编程之: 变量类型

2013/09/30
1
阅读需 12 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

 

14.8  变量类型

ARM C编译器支持基本的数据类型:char、short、int、long long、float和double。表14.2说明了armcc对C语言所使用的数据类型的映射。

表14.2 C编译器数据类型映射

C数据类型

表示的意义

char

无符号8位字节数据

short

有符号16位半字数据

int

有符号32位字数据

long

有符号32位字数据

long long

有符号64位双字数据

ARM指令集中,无论是数据处理指令还是数据加载/存储指令,处理的数据类型不同,指令的执行效率是不一样的。本章将详细讨论,如何在程序中为变量分配合理的数据类型,来提高代码的执行效率。

14.8.1  局部变量

ARM属于RISC的体系结构,所有大多数的数据处理都是在32位的寄存器中进行的。基于这个原因,局部变量应尽可能使用32位数据类型int或long。

注意

一些情况下不得不使用char或short类型,例如要使用char或short类型的数据溢出指令时归零特性时,如模运算255+1=0,就要使用char类型。

为了说明局部变量类型的影响,先来看一个简单的例子。

char charinc (char a)

{

return a + 1;

}

编译出的结果如下。

charinc

          ADD      a1,a1,#1

          AND      a1,a1,#&ff

          MOV      pc,lr

再把上面的程序段中变量a声明位int型,代码如下。

int wordinc (int a)

{

return a + 1;

}

比较一下编译器输出结果。

wordinc

          ADD      a1,a1,#1

          MOV      pc,lr

分析上面的两段代码不难发现,当把变量声明为char型时,编译器增加了额外的ADD指令来保证其范围在0~255之间。

14.8.2  有符号数和无符号数

上一节讨论了对于局部变量和函数参数,使用int型比使用char或short型要好。本节将对程序中的有符号整数(signed int)和无符号整数(unsigned int)的执行效率进行分析比较。

首先来看上一节的例子,如果将变量指定为有符号的半字类型(编译器默认short型为有符号类型),程序的源代码如下。

short shortinc (short a)

{

return a + 1;

}

编译后的结果如下。

shortinc

          ADD      a1,a1,#1

          MOV      a1,a1,LSL #16

          MOV      a1,a1,ASR #16

          MOV      pc,lr

分析发现,该结果比使用int型的变量多增加了两条指令(LSL和ASR)。编译器先将变量左移16位,然后右移16位,以实现一个16位符号扩展。右移是符号位扩展移位,它复制了符号位来填充高16位。

通常情况下,如果程序中只有加法、减法和乘法,那么有符号和无符号数的执行效率相差不大。但是,如果有了除法,情况就不一样了。详细内容可参加除法运算优化一节。

 

14.8.3  全局变量

1.边界对齐

对于RISC体系结构的处理器来说,访问边界对齐的数据要比访问非对齐的数据更高效。表14.3显示了ARM结构下各数据类型所占的字节数。

表14.3 各数据类型所占字节数

C数据类型

所占字节数

char,singed char,unsigned char

1

short,unsigned short

2

int,unsigned int,long,unsigned long

4

float

4

double

4

long long

4

变量定义虽然很简单,但是也有很多值得注意的地方。先看下面的例子。

定义1:

char  a;

short  b;

char  c;

int  d;

定义2:

char  a;

char  c;

short  b;

int  d;

这里定义的4个变量形式都一样,只是次序不同,却导致了在最终映像中不同的数据布局,如同14.1所示,其中pad为无意义的填充数据。

图14.1  变量在数据区里的布局

从图中可以看出,第二种方式节约了更多的存储器空间。

由此可见,在变量声明的时候需要考虑怎样最佳的控制存储器布局。当然,编译器在一定程度上能够优化这类问题,但最好的方法还是在编译的时候把所有相同类型的变量放在一起定义。

2.访问外部变量

首先来看一个例子。下面的例子定义了一些全局变量,在main( )中为这些变量赋值并将其打印输出。

/************

* access.c *

************/

#include <stdio.h>

char tx;

char rx;

char byte;

char c;

unsigned state;

unsigned flags;

int main ()

{ tx = 1;

rx = 2;

byte = 3;

c = 4;

state = 5;

flags = 6;

printf("%u %u %u %u %u %un", tx, rx, byte, c, state, flags);

return 0;

}

使用armcc编译,生成的代码大小如下。

C$$code 132

C$$data 12

如果将全局变量声明为extern,变量的定义在其他文件中,那么生成的代码量将有所增加。

将全局变量声明为extern,生成的代码大小如下。

C$$code 168

C$$data 12

这是因为当将变量声明为extern后,每次访问变量编译器都将从内存重新加载,而不是使用内存偏移,直接访问。

下图显示编译器对声明为extern变量的访问。

解决的办法是将要从外部引用的extern变量定义在一个结构体中。在程序中通过结构体访问外部变量。具体用法如下例所示。

/*************

* globals.h *

*************/

/* DECLARATIONS of globals - included in all sources */

#ifdef __arm

struct globs

{ char tx;

char rx;

图14.2  对extern变量的访问

 

char byte;

char c;

unsigned state;

unsigned flags;

};

extern struct globs g;

#define tx g.tx

#define rx g.rx

#define byte g.byte

#define c g.c

#define state g.state

#define flags g.flags

#else

extern char tx;

extern char rx;

extern char byte;

extern char c;

extern unsigned state;

extern unsigned flags;

#endif

/*************

* globals.c *

*************/

/* DEFINITIONS of globals - single source file */

#ifdef __arm

# include "globals.h"

struct globs g;

#else

char tx;

char rx;

char byte;

char c;

unsigned state;

unsigned flags;

#endif

/************

* access.c *

************/

#include <stdio.h>

#include "globals.h"

int main ()

{tx = 1;

rx = 2;

byte = 3;

c = 4;

state = 5;

flags = 6;

printf("%u %u %u %u %u %un", tx, rx, byte, c, state, flags);

return 0;

}

将变量定义在结构体内有以下几点好处。

·  全局变量使用更小的内存空间。(没有使用结构体占有24字节,而使用结构体之后只占有12字节)

·  全局变量被放置在ZI段而不是RW段,这样就减少了ROM映像文件的大小。

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
DSC1123CI2-125.0000 1 Microchip Technology Inc CRYSTAL OSCILLATOR, CLOCK, 125MHz, LVDS OUTPUT

ECAD模型

下载ECAD模型
$2.44 查看
TJA1042TK/3,118 1 NXP Semiconductors TJA1042 - High-speed CAN transceiver with Standby mode SON 8-Pin

ECAD模型

下载ECAD模型
$1.3 查看
NC7SZ74K8X 1 Fairchild Semiconductor Corporation D Flip-Flop, LVC/LCX/Z Series, 1-Func, Positive Edge Triggered, 1-Bit, Complementary Output, CMOS, PDSO8, 3.10 MM, MO-187CA, US-8
$0.56 查看
Arm

Arm

ARM公司是一家知识产权(IP)供应商,主要为国际上其他的电子公司提供高性能RISC处理器、外设和系统芯片技术授权。目前,ARM公司的处理器内核已经成为便携通讯、手持计算设备、多媒体数字消费品等方案的RISC标准。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知识产权(IP)供应商,主要为国际上其他的电子公司提供高性能RISC处理器、外设和系统芯片技术授权。目前,ARM公司的处理器内核已经成为便携通讯、手持计算设备、多媒体数字消费品等方案的RISC标准。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相关推荐

电子产业图谱

华清远见(www.farsight.com.cn)是国内领先嵌入师培训机构,2004年注册于中国北京海淀高科技园区,除北京总部外,上海、深圳、成都、南京、武汉、西安、广州均有直营分公司。华清远见除提供嵌入式相关的长期就业培训、短期高端培训、师资培训及企业员工内训等业务外,其下属研发中心还负责嵌入式、Android及物联网方向的教学实验平台的研发及培训教材的出版,截止目前为止已公开出版70余本嵌入式/移动开发/物联网相关图书。企业理念:专业始于专注 卓识源于远见。企业价值观:做良心教育、做专业教育,更要做受人尊敬的职业教育。