副标题#e#
概述
C语言的内存模子根基上对应了此刻von Neumann(冯·诺伊曼)计较机的实际存储模子,很好的到达了对呆板的映射,这是C/C++适合做底层开拓的主要原因,别的,C语言适合做底层开拓尚有别的一个原因,那就是C语言对底层操纵做了许多的的支持,提供了许多较量底层的成果。
下面团结问题别离举办叙述。
问题:移位操纵
在运用移位操纵符时,有两个问题必需要清楚:
(1)、在右移操纵中,腾空位是填 0 照旧标记位;
(2)、什么数可以作移位的位数。
谜底与阐明:
">>"和"<<"是指将变量中的每一位向右或向左移动, 其凡是形式为:
右移: 变量名>>移位的位数
左移: 变量名<<移位的位数
颠末移位后, 一端的位被"挤掉",而另一端空出的位以0 填补,在C语言中的移位不是轮回移动的。
(1) 第一个问题的谜底很简朴,但要按照差异的环境而定。假如被移位的是无标记数,则填 0 。假如是有标记数,那么大概填 0 或标记位。假如你想办理右移操纵中腾空位的填充问题,就把变量声明为无标记型,这样腾空位会被置 0。
(2) 第二个问题的谜底也很简朴:假如移动 n 位,那么移位的位数要不小于 0 ,而且必然要小于 n 。这样就不会在一次操纵中把所有数据都移走。
好比,假如整型数据占 32 位,n 是一整型数据,则 n << 31 和 n << 0 都正当,而 n << 32 和 n << -1 都不正当。
留意纵然腾空位填标记位,有标记整数的右移也不相当与除以 。为了证明这一点,我们可以想一下 -1 >> 1 不行能为 0 。
问题:位段布局
struct RPR_ATD_TLV_HEADER
{
ULONG res1:6;
ULONG type:10;
ULONG res1:6;
ULONG length:10;
};
位段布局是一种非凡的布局, 在需按位会见一个字节或字的多个位时, 位布局比按位运算符越发利便。
位布局界说的一般形式为:
struct位布局名{
数据范例 变量名: 整型常数;
数据范例 变量名: 整型常数;
} 位布局变量;
个中: 整型常数必需长短负的整数, 范畴是0~15, 暗示二进制位的个数, 即暗示有几多位。
变量名是选择项, 可以不定名, 这样划定是为了分列需要。
譬喻: 下面界说了一个位布局。
struct{
unsigned incon: 8; /*incon占用低字节的0~7共8位*/
unsigned txcolor: 4;/*txcolor占用高字节的0~3位共4位*/
unsigned bgcolor: 3;/*bgcolor占用高字节的4~6位共3位*/
unsigned blink: 1; /*blink占用高字节的第7位*/
}ch;
位布局成员的会见与布局成员的会见沟通。
譬喻: 会见上例位布局中的bgcolor成员可写成:
ch.bgcolor
位布局成员可以与其它布局成员一起利用。 按位会见与配置,利便&节减
譬喻:
struct info{
char name[8];
int age;
struct addr address;
float pay;
unsigned state: 1;
unsigned pay: 1;
}workers;'
上例的布局界说了关于一个工从的信息。个中有两个位布局成员, 每个位布局成员只有一位, 因此只占一个字节但生存了两个信息, 该字节中第一位暗示工人的状态, 第二位暗示人为是否已发放。由此可见利用位布局可以节减存贮空间。
留意不要高出值限制
#p#副标题#e#
问题:字节对齐
我在利用VC编程的进程中,有一次挪用DLL中界说的布局时,觉察布局都乱掉了,完全不能读取正确的值,厥后发明这是因为DLL和挪用措施利用的字节对齐选项差异,那么我想问一下,字节对齐毕竟是怎么一回事?
谜底与阐明:
关于字节对齐:
1、 当差异的布局利用差异的字节对齐界说时,大概导致它们之间交互变得很坚苦。
2、 在跨CPU举办通信时,可以利用字节对齐来担保独一性,诸如通讯协议、写驱动措施时候寄存器的布局等。
三种对齐方法:
1、 自然对齐方法(Natural Alignment):与该数据范例的巨细相等。
2、 指定对齐方法 :
#pragma pack(8) //指定Align为 8;
#pragma pack() //规复到原先值
3、 实际对齐方法:
Actual Align = min ( Order Align, Natual Align )
对付巨大数据范例(好比布局等):实际对齐方法是其成员最大的实际对齐方法:
Actual Align = max( Actual align1,2,3,…)
编译器的填充纪律:
1、 成员为成员Actual Align的整数倍,在前面加Padding。
成员Actual Align = min( 布局Actual Align,设定对齐方法)
2、 布局为布局Actual Align的整数倍,在后头加Padding.
例子阐明:
#pragma pack(8) //指定Align为 8
struct STest1
{
char ch1;
long lo1;
char ch2;
} test1;
#pragma pack()
此刻
Align of STest1 = 4 , sizeof STest1 = 12 ( 4 * 3 )
test1在内存中的分列如下( FF 为 padding ):
#p#分页标题#e#
00 -- -- -- 04 -- -- -- 08 -- -- -- 12 -- -- --
01 FF FF FF 01 01 01 01 01 FF FF FF
ch1 -- lo1 -- ch2
#pragma pack(2) //指定Align为 2
struct STest2
{
char ch3;
STest1 test;
} test2;
#pragma pack()
此刻 Align of STest1 = 2, Align of STest2 = 2 , sizeof STest2 = 14 ( 7 * 2 )
test2在内存中的分列如下:
00 — — — 04 — — — 08 — — — 12 — — —
02 FF 01 FF FF FF 01 01 01 01 01 FF FF FF
ch3 ch1 — lo1 — ch2
留意事项:
1、 这样一来,编译器无法为特定平台做优化,假如效率很是重要,就只管不要利用#pragma pack,假如必需利用,也最好仅在需要的处所举办配置。
2、 需要加pack的处所必然要在界说布局的头文件中加,不要依赖呼吁行选项,因为假如许多人利用该头文件,并不是每小我私家都知道应该pack。这出格表示在为别人开拓库文件时,假如一个库函数利用了struct作为其参数,当挪用者与库文件开拓者利用差异的pack时,就会造成错误,并且该类错误很欠好查。
3、 在VC及BC提供的头文件中,除了能正好对齐在四字节上的布局外,都加了pack,不然我们编的Windows措施哪一个也不会正常运行。
4、 在 #pragma pack(n) 后必然不要include其他头文件,若包括的头文件中改变了align值,将发生非预期功效。
5、 不要多人同时界说一个数据布局。这样可以担保一致的pack值。
问题:按位运算符
C语言和其它高级语言差异的是它完全支持按位运算符。这与汇编语言的位操纵有些相似。 C中按位运算符列出如下:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
操纵符 浸染
────────────────────────────
& 位逻辑与
| 位逻辑或
^ 位逻辑异或
– 位逻辑反
>> 右移
<< 左移
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
留意:
1、 按位运算是对字节或字中的实际位举办检测、配置或移位, 它只合用于字符型和整数型变量以及它们的变体, 对其它数据范例不合用。
2、 干系运算和逻辑运算表达式的功效只能是1或0。 而按位运算的功效可以取0或1以外的值。 要留意区别按位运算符和逻辑运算符的差异, 譬喻, 若x=7, 则x&&8 的值为真(两个非零值相与仍为非零), 而x&8的值为0。
3、 | 与 ||,&与&&,~与! 的干系
&、| 和 ~ 操纵符把它们的操纵数看成一个为序列,按位单独举办操纵。好比:10 & 12 = 8,这是因为"&"操纵符把 10 和 12 看成二进制描写 1010 和 1100 ,所以只有当两个操纵数的沟通位同时为 1 时,发生的功效中相应位才为 1 。同理,10 | 12 = 14 ( 1110 ),通过补码运算,~10 = -11 ( 11…110101 )。<以几多为一个位序列> &&、|| 和!操纵符把它们的操纵数看成"真"或"假",而且用 0 代表"假",任何非 0 值被认为是"真"。它们返回 1 代表"真",0 代表"假",对付"&&"和"||"操纵符,假如左侧的操纵数的值就可以抉择表达式的值,它们基础就不去计较右侧的操纵数。所以,!10 是 0 ,因为 10 非 0 ;10 && 12 是 1 ,因为 10 和 12 均非 0 ;10 || 12也是 1 ,因为 10 非 0 。而且,在最后一个表达式中,12 基础就没被计较,在表达式 10 || f( ) 中也是如此。