Chinaunix
标题:
1 还是 -1 ?
[打印本页]
作者:
panweiping
时间:
2011-07-14 20:52
标题:
1 还是 -1 ?
最近在看位序,即bit order。(当然我的问题可能与之无关,也可能有关,我也不知道)
#include <stdio.h>
//#define BYTE unsigned char
#define BYTE char
typedef struct
{
BYTE a:1;
BYTE b:1;
BYTE c:1;
BYTE d:1;
BYTE e:1;
BYTE f:1;
BYTE g:1;
BYTE h:1;
}TestBit;
int main(int argc, char* argv[])
{
char c = 0x96; /* 10010110 */
TestBit *q = NULL;
q = (TestBit *)&c;
printf("q->a = %d\n", q->a);
printf("q->b = %d\n", q->b);
printf("q->c = %d\n", q->c);
printf("q->d = %d\n", q->d);
printf("q->e = %d\n", q->e);
printf("q->f = %d\n", q->f);
printf("q->g = %d\n", q->g);
printf("q->h = %d\n", q->h);
return 0;
}
复制代码
我的问题是在这两个define这里。
当用#define BYTE unsigned char时,输出是:
[pwp@localhost bit_order]$ ./bit_order
q->a = 0
q->b = 1
q->c = 1
q->d = 0
q->e = 1
q->f = 0
q->g = 0
q->h = 1
当时当用#define BYTE char时,输出是:
[pwp@localhost bit_order]$ ./bit_order
q->a = 0
q->b = -1
q->c = -1
q->d = 0
q->e = -1
q->f = 0
q->g = 0
q->h = -1
为什么会是-1呢?
作者:
KBTiller
时间:
2011-07-14 21:13
回复
1#
panweiping
感觉有点怪怪的
为什么 c 不定义成TestBit类型
作者:
panweiping
时间:
2011-07-14 21:29
那怎么赋值呢?
TestBit d = 0x96; /* 10010110 */
编译器报bit_order.c:33:2: error: invalid initializer
当然可以用 TestBit d = { .a=0, .b=1};这样赋值,但是这不是重点,也不是问题的本质所在吧。
作者:
drangon
时间:
2011-07-14 21:39
有符号数,最高位是1,是负数没什么疑问的啊
作者:
KBTiller
时间:
2011-07-14 21:40
回复
3#
panweiping
-1说明char 类型是signed
作者:
vupiggy
时间:
2011-07-15 00:20
drangon 的回答大体靠谱。
在目前流行的编码系统中,判断一个有符号数的正负根据其最高位,那么只有一个位的数而言,那个唯一存在的位同时是其最高位,具体到你的例子,q->b 是一个只有一个位的数,其唯一的位也就是最高位是 1,所以它是负数。换一个角度,n 个位可以表示的有符号数的范围是:[-2^(n-1), 2^(n-1) - 1],譬如:8 个 bit 可以表示的数的范围是:[-128, 127],那么一个位能表示的有符号数范围是什么呢?代入刚才的公式,范围是:[-1, 0],这下释怀了吧。
结论是:单比特的有符号位段不宜直接作为整数使用。
作者:
KBTiller
时间:
2011-07-15 07:04
本帖最后由 KBTiller 于 2011-07-15 07:29 编辑
8.5.2 如何定义位段
在结构体或联合体类型中定义位段成员的一般方法是:
数据类型 [成员名称]:数据宽度;
这里的数据类型可以是“signed int”、“unsigned int”、“int”,这几种类型是标准规定的,此外C99还允许_Bool类型。
有些编译器在此基础上还允许其他类型,比如char类型
。
数据宽度必须是一个非负的整数类型常量表达式。这个数据宽度不允许过大。一般来说,通常以计算机的字长为限。
成员名称是可以省略的,但这样的成员在代码中是无法引用的,其作用是在数据之间起到间隔或填充的作用。这样的位段通常被叫做无名位段。
如果一个无名位段的数据宽度为0,表示的含义是下一位段需要存放到下一个“存储单元”。但这种“存储单元”究竟以什么为单位很难一概而论,通常是由编译器自行定义的,大多数情况下是指一个计算机字。
位段成员同样不能跨越“存储单元”的边界,如果遇到一个“存储单元”中剩余的位数不够存储下一个位段的情况,编译器会将这个字段安排在下一个“存储单元”之中。
8.5.3 位段的性质
位段的值(右值)可以参加运算,运算时一律转换为“signed”类型或“unsigned”类型,但是“int”类型的位段很难说是“signed”类型还是“unsigned”类型。
如果编译器规定“char”类型为“signed ”类型,那么“int”类型的位段也是“signed”类型;反之,如果编译器规定“char”类型为“unsigned ”类型,那么“int”类型的位段也是“unsigned”类型。
位段成员可以被赋值,但基本上无法把位段成员当作左值,因为无法给出位段的位置的C语言表达。位段无法作为左值参与“sizeof”、“&”等左值才能参与的运算,但可以进行“++”、“--”这种运算。
由于C语言无法表达位段的内存位置,所以也不可以构造位段数组。
可以用%d、%x、%u和%o等格式字符,以整数形式输出位段的值。但是由于位段成员无法进行一元“&”运算,所以无法直接通过调用scanf()函数输入位段的数据。
http://book.chinaunix.net/showart.php?id=8555
char位段不属于标准规定的用法,只是某些编译器支持
我认为char位段的性质和int位段的性质一样
其为signed还是unsigned取决于“char”类型是否为“signed ”类型(这一点是我的推测,究竟如何可能还是要看编译器的文档)
作者:
panweiping
时间:
2011-07-15 09:11
释怀了。
谢谢大家。
作者:
狗气球
时间:
2011-07-15 10:34
>>其为signed还是unsigned取决于“char”类型是否为“signed ”类型(这一点是我的推测,究竟如何可能还是要看编译器的文档)
C标准里没有规定char是否有符号。这个取决于编译器实现。
事实上如果想表示取值范围在[-128, 127]的整数,应使用signed char,想表示取值范围在[0, 255]的整数,应使用unsigned char。
只有当要表示可打印的单字节字符时,才应该使用char。
作者:
KBTiller
时间:
2011-07-15 10:36
回复
9#
狗气球
完全同意这个补充
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2