用c++c语言输出矩阵对齐对齐输出

编程时为什么需要对齐&以及怎样对齐
编程时为什么需要对齐&以及怎样对齐
  什么是对齐,以及为什么要对齐:&&& 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。&&& 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效&&& 率上下降很多。这也是空间和时间的博弈。&&& 对齐的实现&&& 通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。&&& 但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是strUCt数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。&&& 对齐的算法:&&& 由于各个平台和编译器的不同,现以本人使用的gcc version 3.2.2编译器(32位x86平台)为例子,来讨论编译器对struct数据结构中的各成员如何进行对齐的。&&& 设结构体如下定义:&&& struct A&&& {&&&&&&&&&&&& };&&& 结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个。所以A用到的空间应该是7字节。但是因为编译器要对数据成员在空间上进行对齐。&&& 所以使用sizeof(strcut A)值为8。&&& 现在把该结构体调整成员变量的顺序。&&& struct B&&& {&&&&&&&&&&&& };&&& 这时候同样是总共7个字节的变量,但是sizeof(struct B)的值却是12。&&& 下面我们使用预编译指令#progma pack (value)来告诉编译器,使用我们指定的对齐值来取代缺省的。&&& #progma pack (2) /*指定按2字节对齐*/&&& struct C&&& {&&&&&&&&&&&& };&&& #progma pack () /*取消指定对齐,恢复缺省对齐*/&&& sizeof(struct C)值是8。
  修改对齐值为1:&&& #progma pack (1) /*指定按1字节对齐*/&&& struct D&&& {&&&&&&&&&&&& };&&& #progma pack () /*取消指定对齐,恢复缺省对齐*/&&& sizeof(struct D)值为7。
  对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。&&& 这里面有四个概念值:&&& 1.数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。
  2.指定对齐值:#progma pack (value)时的指定对齐值value。
  3.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。&&& 4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。&&& 有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解)。这样就不能理解上面的几个例子的值了。&&& 例子分析:&&& 分析例子B;&&& struct B&&& {&&&&&&&&&&&& };&&& 假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4,所以只能存放在起始地址为0x7这四个连续的字节空间中,复核0x,且紧靠第一个变量。第三个变量c,自身对齐值为2,所以有效对齐值也是2,可以存放在0x9这两个字节空间中,符合0x。所以从0x9存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0xB共有12个字节,sizeof(struct B)=12;
  同理,分析上面例子C:&&& #progma pack (2) /*指定按2字节对齐*/&&& struct C&&& {&&&&&&&&&&&& };&&& #progma pack () /*取消指定对齐,恢复缺省对齐*/&&& 第一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,假设C从0x0000开始,那么b存放在0x0000,符合0x;第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,所以顺序存放在0x3、0x5四个连续字节中,符合0x。第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放&&& 在0x7中,符合0x。所以从0x07共八字节存放的是C的变量。又C的自身对齐值为4,所以C的有效对齐值为2。又8%2=0,C只占用0x7的八个字节。所以sizeof(struct C)=8.
&&&主编推荐
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
港口与航道工程建设工程法规及相关知识建设工程经济考试大纲矿业工程市政公用工程通信与广电工程
操作系统汇编语言计算机系统结构人工智能数据库系统微机与接口
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
Powerpoint教程WPS教程
电子政务客户关系管理首席信息官办公自动化大数据
职称考试题目
就业指导签约违约职业测评
招生信息考研政治
网络安全安全设置工具使用手机安全
3DMax教程Flash教程CorelDraw教程Director教程
Dreamwaver教程HTML教程网站策划网站运营Frontpage教程
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
互联网电信IT业界IT生活
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
组织运营财务资本
视频播放文件压缩杀毒软件输入法微博
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&C/C++数据对齐详细解析
字体:[ ] 类型:转载 时间:
通常我们在写代码的时候是不需要考虑对齐的影响的,都是依赖编译器来为我们选择适合的对齐策略,我们也可以通过传递给编译器预编译指令来指定数据对齐的方法
Data Alignment
关于数据对齐问题,现在多多少少有了一些接触,简单地说下自己的看法。
1、对齐的背景
大端和小端的问题有必要在这里介绍一下,计算机里面每个地址单元对应着一个字节,一个字节为8bit,对于位数大于8位的处理器来说,寄存器的宽度是大于一个字节的,例如16bit的short型变量x,在内存中的地址是0x0010,x的值为0x为高字节,0x22为低字节,常用的X86结构是小端模式,很多ARM,DSP都是小端模式,而KEIL C51则为大端模式。内存空间是按照byte进行划分的,理论上对任何类型的变量的访问可以从任何地址开始,但实际上访问特定变量的时候经常在特定的内存地址访问,这就需要各类型的数据按照一定的规则在空间上排列,而不是顺序排列,这就是对齐。
2、对齐的原因
不同硬件平台对存储空间的处理是有很大不同的,一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
3、对齐的实现
通常我们在写代码的时候是不需要考虑对齐的影响的,都是依赖编译器来为我们选择适合的对齐策略,我们也可以通过传递给编译器预编译指令来指定数据对齐的方法。
以struct数据结构的sizeof方法为例,环境是Mac OS X 64位内核,结构体的定义如下:
struct A {};
struct B {};
#pragma pack(2)struct C {};#pragma pack()
#pragma pack(1)struct D {};#pragma pack()
int main(int argc, char** argv){printf("size of struct A : %lu \n", sizeof(struct A));printf("size of struct B : %lu \n", sizeof(struct B));printf("size of struct C : %lu \n", sizeof(struct C));printf("size of struct D : %lu \n", sizeof(struct D));return 0;}
输出:size of struct A : 8size of struct B : 12size of struct C : 8size of struct D : 7
结构体中包含了4字节长度的int一个,1字节长度的char一个以及2字节长度的short一个。加起来所用到的内存空间为7个字节,但实际使用sizeof时发现,结构体之间占用的内存是不一样的。
关于对齐有几个需要说明的:(1)数据类型自身的对齐值:基本数据类型的自身对齐值,char类型为1,short类型为2,int,float,double为4;
(2)指定对齐值:#pragma pack(value)时的指定对齐值value;
(3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值;
(4)数据成员、结构体和类的有效对齐值:自身对齐值或指定对齐值中较小值。
对于一个具体的数据结构的成员和其自身的对齐方式,有效对齐值N将最终决定数据存放地址的方式的值,对齐在N上就意味着数据“存放的起始地址%N=0”,
下面来针对上面的例子进行分析:struct B {};
假设B从地址空间0x0000开始,默认的对齐值是4(这里有个问题想请教大家,我的是64位的内核,但是测试我的默认对齐方式为4),第一个成员变量b的自身对齐值为1,比默认值小所以有效对齐值为1,存放地址0x,第二个成员变量a,自身对齐值为4,存放的起始地址为0x7这个4个连续的字节空间中,0x,第三个变量c,自身对齐值为2,存放的起始地址为0x9,地址同样符合要求。结构体B的自身对齐值为变量中的最大对齐值(b)4,(10+2)%4=0,所以0x000A到0x000B也是被结构体B占用。内存中的示意图:b - - -a a a ac c
#pragma pack(2)struct C {};#pragma pack()
第一个变量b的自身对齐值为1,指定对齐值为2,有效对齐值为1,b存放在0x0000,a的自身对齐值为4,大于指定对齐值,所有有效的对齐值为2,a占有的字节为0x3、0x5四个连续字节中,c的自身对齐值为2,所以有效对齐值也是2,顺序存放在0x7。结构体C的自身对齐值为4,所以有效对齐值为2,8%2=0。内存中的示意图:b -a aa ac c
其实想到内存中的示意图一切都会简单很多。
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具Printf()输出格式控制
Printf()输出格式控制
1.转换说明符
&&&&& %a(%A)&&&& 浮点数、十六进制数字和p-(P-)记数法(C99)
&&&&& %c&&&&&&&&&&&& 字符
&&&&& %d&&&&&&&&&&&& 有符号十进制整数
&&&&& %f&&&&&&&&&&&&& 浮点数(包括float和doulbe)
&&&&& %e(%E)&&&& 浮点数指数输出[e-(E-)记数法]
&&&&& %g(%G)&&&& 浮点数不显无意义的零&0&
&&&&& %i&&&&&&&&&&&&& 有符号十进制整数(与%d相同)
&&&&& %u&&&&&&&&&&&& 无符号十进制整数
&&&&& %o&&&&&&&&&&&& 八进制整数&&& e.g.&&&& 0123
&&&&& %x(%X)&&&&& 十六进制整数0f(0F)&& e.g.&& 0x1234
&&&&& %p&&&&&&&&&&&& 指针
&&&&& %s&&&&&&&&&&&& 字符串
&&&&& %%&&&&&&&&&&& &%&
&&&&& 左对齐:&-&&& e.g.&& &%-20s&
&&&&& 右对齐:&+&& e.g.&& &%+20s&
&&&&& 空格:若符号为正,则显示空格,负则显示&-&&& e.g.&& &%& 6.2f&&&&&&
&&&&& #:对c,s,d,u类无影响;对o类,在输出时加前缀o;对x类,在输出时加前缀0x;
&&&&&&&&&& 对e,g,f 类当结果有小数时才给出小数点。
3.格式字符串(格式)
&&&&& [标志][输出最少宽度][.精度][长度]类型
&&&& &%-md& :左对齐,若m比实际少时,按实际输出。
&&&& &%m.ns&:输出m位,取字符串(左起)n位,左补空格,当n&m or m省略时m=n
&&&&&&&&&&&&&&&&&&&&& e.g.&&& &%7.2s&&& 输入CHINA
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&  &&&&&&&&&& 输出&&&&& CH&
&&&& &%m.nf&:输出浮点数,m为宽度,n为小数点右边数位
&&&&&&&&&&&&&&&&&&&&& e.g.&&& &%3.1f&&&& 输入3852.99
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 输出3853.0
&&&&& 长度:为h短整形量,l为长整形量
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

我要回帖

更多关于 c语言左对齐输出 的文章

 

随机推荐