C语言struct位域符号问题

来源:互联网 发布:java 引用class文件 编辑:程序博客网 时间:2024/05/16 00:40

C语言位域符号问题

1. 引言

本来没打算写这篇文章,但最近在项目中遇到了位域这个问题,问题大概就是,在没有越界的情况下,一个位域吃进去的值和吐出来的值居然不一样,虽然知道位域这个东西比较节省空间,但从没有深究这个东西,现在既然遇到坑了,就研究了一下,拿出来和大家分享一下,也不是很难的东西,算是生活常识吧。

2. 结论及测试程序

由于知识点比较简单,我就先说结论吧。结论就是:(1)对于有符号类型的位域,最高位会被解析为符号位,在进行%d输出时,会以算术移位进行位扩展。比如一个位域 int32_t a : 4, 在进行%d输出时,会将a从4位扩展成32位,中间扩展的内容和符号位相同,即算术移位;(2)对于无符号类型的位域,不存在符号位,在进行扩展时,扩展位全部补0。测试程序如下:

#include <iostream>#include <stdio.h>#include <stdint.h>using namespace std;struct SignedNode {    int32_t a : 2;    int32_t b : 2;    int32_t c : 2;};struct UnsignedNode {    uint32_t a : 2;    uint32_t b : 2;    uint32_t c : 2;};int main(int args, char *arg[]) {    SignedNode s_node;    UnsignedNode us_node;     s_node.a = 1;    s_node.b = 2;    s_node.c = 3;    us_node.a = 1;    us_node.b = 2;    us_node.c = 3;    printf("SignedNode Dec Value: a = %d, b = %d, c = %d\n", s_node.a, s_node.b, s_node.c);    printf("UnsignedNode Dec Value: a = %d, b = %d, c = %d\n", us_node.a, us_node.b, us_node.c);    printf("SignedNode Hex Value: a = %p, b = %p, c = %p\n", s_node.a, s_node.b, s_node.c);    printf("UnsignedNode Hex Value: a = %p, b = %p, c = %p\n", us_node.a, us_node.b, us_node.c);    return 0;}
测试环境为:gcc 4.8.2

测试结果为:

SignedNode Dec Value: a = 1, b = -2, c = -1
UnsignedNode Dec Value: a = 1, b = 2, c = 3
SignedNode Hex Value: a = 0x1, b = 0xfffffffe, c = 0xffffffff
UnsignedNode Hex Value: a = 0x1, b = 0x2, c = 0x3

3.测试结果分析

(1)SignedNode的测试中,a,b,c各占2位,二进制分别位01,10,11,符号位的值分别位0,1,1,它们的类型仍旧是int32_t,在进行%d输出时,会把它们扩展成int32_t类型,扩展后变成a = 0x00000001,b = 0xFFFFFFFE,c = 0xFFFFFFFF,转换成十进制也就是1,-2,-1。

(2)UnsignedNode的测试中,a,b,c也各占2位,二进制分别为01,10,11,由于都是uin32_t类型,所以不存在符号位,但仍旧需要扩展成uint32_t类型,所以直接高位补0即可,扩展后变成a = 0x00000001,b = 0x00000002,c = 0x00000003,转换成十进制也就是1,2,3。


综上所示,位域的扩展实际和位域本身的类型息息相关,对于有符号类型和无符号类型扩展后的结果不同,但二者扩展的原理相同。我尝试过用共用体按字节打印出SignedNode的内容,但每次输出的结果都不同,看不出位域在存储层面的结构,而且位域地址打印也不合法,可能是自己方法不得当,如果有哪位大神知道如何从存储层面分析位域的好方法,还望指点一二,不甚感激。

原创粉丝点击