游乐场收银员七大话术:一道c语言题

来源:百度文库 编辑:查人人中国名人网 时间:2024/04/30 11:24:47
#include <stdio.h>

typedef struct {

int a : 1;
int b : 1;
int c : 1;
} m;

int main(int argc,char *argv[])
{
m k;
k.a = 1;
k.b = 0;
k.c = 0;

printf("%d, %d, %d, %d\n", sizeof(k), k.a, k.b, k.c);
return 0;
}

1.给出输出结果,并解释

输出为4,-1,0,0

这个题目很有意思,所以有必要给LZ详细解释一下,sizeof应该没有任何问题,虽然由于位域的关系导致只用了最后的3位,但是由于字节对齐的规则,整个结构大小必须是第一个元素的类型的整数倍,所以应该是4.

最有意思的是这个-1的由来,看了楼上几位XD的分析,感觉有很多地方需要详细的说明一下.先看下面的汇编.[使用VC6编译器]:
12: m k;
13: k.a = 1;
00401548 mov eax,dword ptr [ebp-4]
0040154B or al,1
0040154D mov dword ptr [ebp-4],eax
14: k.b = 0;
00401550 mov ecx,dword ptr [ebp-4]
00401553 and ecx,0FFFFFFFDh
00401556 mov dword ptr [ebp-4],ecx
15: k.c = 0;
00401559 mov edx,dword ptr [ebp-4]
0040155C and edx,0FFFFFFFBh
0040155F mov dword ptr [ebp-4],edx
16:
17: printf("%d, %d, %d, %d\n", sizeof(k), k.a, k.b, k.c);
00401562 mov eax,dword ptr [ebp-4]
00401565 shl eax,1Dh
00401568 sar eax,1Fh
0040156B push eax
0040156C mov ecx,dword ptr [ebp-4]
0040156F shl ecx,1Eh
00401572 sar ecx,1Fh
00401575 push ecx
00401576 mov edx,dword ptr [ebp-4]
00401579 shl edx,1Fh
0040157C sar edx,1Fh
0040157F push edx
00401580 push 4
00401582 push offset string "%d, %d, %d, %d\n" (0042d0b4)
00401587 call printf (004019d0)
0040158C add esp,14h

1.下面的段是很容易理解的,注释一下:
12: m k;
13: k.a = 1;
00401548 mov eax,dword ptr [ebp-4]
0040154B or al,1 '最低1位赋值1,为a
0040154D mov dword ptr [ebp-4],eax
14: k.b = 0;
00401550 mov ecx,dword ptr [ebp-4]
00401553 and ecx,0FFFFFFFDh '次低位赋值0,为b
00401556 mov dword ptr [ebp-4],ecx
15: k.c = 0;
00401559 mov edx,dword ptr [ebp-4]
0040155C and edx,0FFFFFFFBh '第3位赋值0,为c
0040155F mov dword ptr [ebp-4],edx

2.关键在于输出的时候编译器的操作,从下面的段可以发现,编译器输出是直接通过左移去掉显示的位左边的所有位,再通过右移去掉显示的位的右边的所有位,举个例子比如:二进制 01010101,我想显示最后的1,那么我先左移7位,去掉左边的0101010,得10000000,然后再右移7位,得00000001,这样成功输出最后1位1.但是编译器在这步操作得时候,左移是逻辑左移shl,而右移是算术右移sar,问题就出来了,当右移得时候,由于是算术右移,那么他填充得是MSB这个位,也就是说,左边填充得不是0,而是最左位,那么碰到诸如10000000,这样得算术右移会变成11111111,这个是什么东西,呵呵,其实就是-1了.所以造成这样古怪得输出,简单得注释下面一段:

17: printf("%d, %d, %d, %d\n", sizeof(k), k.a, k.b, k.c);
00401562 mov eax,dword ptr [ebp-4]
00401565 shl eax,1Dh '求出c入栈,先逻辑左移1D
00401568 sar eax,1Fh '再算术右移1F,这个时候由于C是0,所以还是0
0040156B push eax
0040156C mov ecx,dword ptr [ebp-4]
0040156F shl ecx,1Eh 'B是和C一样得.
00401572 sar ecx,1Fh
00401575 push ecx
00401576 mov edx,dword ptr [ebp-4]
00401579 shl edx,1Fh '这个是a,注意由于a是1
0040157C sar edx,1Fh'所以移回全部填充MSB这个位1,导致a变成负得了
0040157F push edx
00401580 push 4 '这个是sizeof()
00401582 push offset string "%d, %d, %d, %d\n" (0042d0b4)
00401587 call printf (004019d0)
0040158C add esp,14h

希望我得解释能给LZ帮助.

没试过。由于在家过年,电脑中没有任何编程工具,
故I don't know。

typedef struct {
int a : 1;
int b : 1;
int c : 1;
} m;
我不知道typedef 是不是可以这么用
我先举个它的小例子:
typedef uchar unsigned char;
所以我对typedef这部分有点看法。
今天刚注册了个帐号,菜鸟一个,不妥之处请海涵。

4(或8) -1 0 0

解释:sizeof有一个特点,如果不够4(或8)个字节,他也会输出四(如果是64位就应该是8)。如果看这个struct应该只有3个bit,但应该输出4。第二,这是c语言,c的Int是有符号的,第一位永远是符号为,所以如果只有一个Bit,设置为1时,就是加了个符号,就应该是-1。

我是在turbo环境下运行的,这里的int型是2个字节
所以sizeof(int)=2

输出时1,-1,0,0而不是6,1,0,0

这里问题出在
int a : 1;
int b : 1;
int c : 1; 这里有冒号,这个冒号是用于位分割

可以通过一个例子来了解冒号的作用

比如说有16位数据,被分为9位和7位的两个域,就可以这样定义:
typedef struct{
int 9_bit :9;
int 7_bit :7;
}Type;
在上面的例子中,16位的数据就被分割成两部分,低9位的名字叫做9_bit,高7位的名字叫做7_bit,定义该类型的变量后,变量的两个域就可以被赋值和调用了.

所以程序中int a : 1;表示这为最低一位的名字,b为次一位,c为最高一位

在机器数中,第一位为零的表示这个十进制数是负数,如01表示 -1
a=1,b=0,c=0所以将3位赋值为001,但空间最少应该是1字节8位,高位补0 输出时%d表示输出的十进制数对于第一位a就是-1
b=0 c=0

sizeof(k)=1表示这是一个字节,因为我们总共就设定了3位,不足1字节按照1字节来算。

同理的
typedef struct {

int a : 1;1位按照以字节算
int b ;2字节
int c ;2字节
} m;
这里的sizeof(m)=5字节

typedef struct {

int a : 1;1位
int b : 1;1位,以上两位不足1字节,按照1字节算
int c : ;2字节
} m;
这里的sizeof(m)=3字节

ps 16位的turbo c int为2字节,所以sizeof(int)=2
而c++等编制32位程序时 int是4字节sizeof(int)=4

++++++++++++++++
12,-1,0,0
(这有一个回车)
++++++++++++++++
关于int是要根据不同的编译器而确定的.
在vc++6.0里是32位(4字节),

typedef struct {

int a : 1;
int b : 1;
int c : 1;
} m;

结构型变量m
定义 m型变量 k (就想定义int型变量k差不多的解释,m即变量类型)
tc运算结果
1 ,-1 , 0 , 0