文章目录
2.55*
问:在你能访问的不同的机器上,编译show_bytes.c
并运行代码,确定这些机器的字节顺序。
答:
// show_bytes.c
#include <stdio.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, size_t len)
{
for (size_t i = 0; i < len; ++i) {
printf("%.2X ", start[i]);
}
printf("\n");
}
void show_int(int x)
{
show_bytes((byte_pointer)&x, sizeof(int));
}
在x86_64
上,运行结果为:
// show_int(0x87654321);
[liheng@localhost2 2]$ ./a.out
21 43 65 87
低位字节保存在低地址,该机器按小端顺序存储多字节对象。
2.56*
问:试着用不同的示例值来运行show_bytes.c
。
答:
// show_int(0x11223344);
[liheng@localhost2 2]$ ./a.out
44 33 22 11
// show_int(0x22);
[liheng@localhost2 2]$ ./a.out
22 00 00 00
// show_int(0x11000000);
[liheng@localhost2 2]$ ./a.out
00 00 00 11
2.57*
问:编写并运行程序show_short
、show_long
和show_double
。
答:
void show_short(short x)
{
show_bytes((byte_pointer)&x, sizeof(short));
}
void show_long(long x)
{
show_bytes((byte_pointer)&x, sizeof(long));
}
void show_double(double x)
{
show_bytes((byte_pointer)&x, sizeof(double));
}
在x86_64
上,运行结果为:
// show_short(0x1234);
// show_long(0x1234);
// show_double(0x1234);
[liheng@localhost2 2]$ ./a.out
34 12
34 12 00 00 00 00 00 00
00 00 00 00 00 34 B2 40
// show_short(0x1030);
// show_long(0x1030);
// show_double(0x1030);
[liheng@localhost2 2]$ ./a.out
30 10
30 10 00 00 00 00 00 00
00 00 00 00 00 30 B0 40
2.58**
问:编写过程is_little_endian
,当在小端法机器上运行时返回1
,否则返回0
。
答:
int is_little_endian()
{
uint32_t x = 0x12345678; // #include <stdint.h>
return *(uint8_t *)&x == (uint8_t)0x78;
}
在x86_64
上,运行结果为:
// printf("is_little_endian: %d\n", is_little_endian());
[liheng@localhost2 2]$ ./a.out
is_little_endian: 1
2.59**
问:编写一个C
表达式,它生成一个字,由x
的最低有效字节和y
中剩下的字节组成。对于x = 0x89ABCDEF
、y = 0x76543210
得到0x765432EF
。
答:表达式为(x & 0xFF) | (y & ~0xFF)
。
2.60**
问:假设我们将一个w
位的字中的字节从0
(最低位字节)到w / 8 - 1
(最高位字节)编号,写出下面C
函数的代码,它会返回一个无符号值,其中参数x
的字节i
被替换成字节b
。
unsigned replace_byte(unsigned x, int i, unsigned char b);
// replace_byte(0x12345678, 2, 0xAB) --> 0x12AB5678
// replace_byte(0x12345678, 0, 0xAB) --> 0x123456AB
答:
replace_byte
的实现:
unsigned replace_byte(unsigned x, int i, unsigned char b)
{
unsigned bits = i << 3;
unsigned x1 = x & ~(0xFF << bits);
unsigned b1 = b << bits;
return x1 | b1;
}
在x86_64
上的运行结果:
// printf("%p\n", replace_byte(0x12345678, 4, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 3, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 2, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 1, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 0, 0xAB));
[liheng@localhost2 2]$ ./a.out
0x123456ab
0xab345678
0x12ab5678
0x1234ab78
0x123456ab
位级整数编码规则
在接下来的作业中,我们特意限制了你能使用的编程结构,来帮助你更好地理解C
语言的位级、逻辑和算术运算。你的代码必须遵守以下规则:
- 假设
- 整数用补码形式表示。
- 有符号数的右移是算术右移。
- 数据类型
int
是w
(一定是8
的整数倍)位长的。某些题目会给出w
的值。
- 禁止使用
- 条件语句
if
或? :
、循环、分支语句、函数调用和宏调用。 - 除法、模运算和乘法。
- 相对比较运算
<
、>
、<=
和>=
。
- 允许的运算
- 所有的位级和逻辑运算。
- 左移和右移,位移量只能在
0 ~ w-1
之间。 - 加法和减法。
- 相等
==
和不相等!=
。 - 整型常数
INT_MIN
和INT_MAX
。 - 对
int
和unsigned
进行隐式或显式强制类型转换。
个别题目有特殊的限制。
2.61**
问:写一个C
表达式,在下列描述的条件下产生1
,在其他情况下得到0
,假设x
是int
类型。
答:
x
的任何位都等于1
。
!~x
x
的任何位都等于0
。
!x;
x
的最低有效字节中的位都等于1
。
!~(x | ~0xFF)
x
的最高有效字节中的位都等于0
。
!((0xFF << ((sizeof(int) - 1) << 3)) & x);
2.62***
问:编写一个函数int_shifts_are_arithmetic()
,在对int
类型的数使用算术右移的机器上运行时这个函数返回1
,其他情况下返回0
。
答: