1.如何用程序判断自己的机器是大端还是小端?


通常情况下,我们的计算机都是小端存储模式。

小端:数字的低位存储到内存的低地址上。

大端:数字的低位存储到内存的高地址上。

我们在 VS 中创建一个临时变脸

int a = 0x11223344;// 十六进制数

然后打开调试器,看到变量 a 在内存中是这样存储的:

0x0133FC50  44 33 22 11

对于 Vs 调试中内存窗口的这行信息应该如何理解呢?它就表示:

十六进制数每两位表示一个字节,地址也是十六进制数;int 类型在 32 位机器上大小为 4 个字节。

如何理解十六进制数每两位表示一个字节?

十六进制数每一位的取值范围是 0 ~ 15,表示 16 种不同可能,对应 4 个二进制位(0000 ~ 1111),所以每一位十六进制可以表示 4 个二进制位,那么两个十六进制位就表示 8 个二进制位,也就是 1 个字节。

可以看到,在我的机器上,低位 44 存储在 低地址(0x0133FC50)上,所以我的机器是 小端存储模式。

如果是大端存储模式,变量 a 在内存中的存储应该如下图所示:

现在,让我们用程序来验证一下我们的机器到底是大端还是小端。

方法一

#include<stdio.h>

int main(void) {

int a = 0x11223344;
int* pi = &a;
char* pc = (char*)pi;//指针强转

printf("%x\n", *pc);//输出 44 ,得到证实

return 0;
}

方法二

#include<stdio.h>

typedef union {
int a;
char ch[sizeof(int)];
}BOS;//big or small

int main(void) {

BOS bos;
bos.a = 0x11223344;

printf("%x", (unsigned int)bos.ch[0]);//输出 44

return 0;
}

2.关于整数类型存储的面试问题


以下问题大家可以先独立思考一下,看看如果真的面试官问你,你能不能正确的回答并清晰的讲出其中的原理。

1

请问,printf 函数会打印出什么内容?并解释原因。

char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a = %d, b = %d, c = %d\n", a, b, c);
a = -1, b = -1, c = 255

signed char 与 char 表示同一种类型,原理一样

2

请问,printf 函数会打印出什么内容?并解释原因。

char a = -128;
printf("%u\n", a);
4294967168

你想到了吗?

我们还是按照上面的思路分析:

3

请问,printf 函数会打印出什么内容?并解释原因。

char a = 128;
printf("%u\n", a);
4294967168

神奇吗?并不神奇。

原因就在于“截断”时得到的二进制序列是一模一样的,后面的操做是相同的。

另外说一句,char 的范围是 -128 ~ 127,所以上面的 char 型变量 a 溢出了。

试着想想下面的 printf 函数又会输出什么呢?

unsigned char a = -128;
unsigned char b = 128;
printf("a = %u, b = %u\n", a, b);

4

int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);

首先,i 与 j 相加时,int 转换为 unsigned int

5

请问:下面的程序会输出什么?

unsigned int i;
for(i = 9; i >= 0; i--){
printf("%u\n", i);
}

这个问题的关键点就是在 i == 0 时。如果 i 的类型是 int ,毫无疑问,for 循环会在这里结束。可是,现在 i 的类型是 unsigned int。

我们知道,i--等同于 i -= 1,也就是 i = i - 1 。对于编译器来说,其实这个操作是 i = i + (-1),我们知道, -1 的补码是:

11111111 11111111 11111111 11111111

当它与 0(i)相加时,i 的补码就变成了全 1。问题就在于,这时候 i 是 unsigned int 类型,这个全 1 的补码的含义并不是 -1 而是 unsigned int 的最大值。所以循环条件 i >= 0 依然满足。

换句话说,对于 unsigned int 类型的 i 来说,i >= 0是恒成立的。

所以答案是无限循环。

6

int main(void)
{
char a[1000];
int i;

for(i=0; i<1000; i++){
a[i] = -1-i;
}

printf("%d",strlen(a));

return 0;
}

7

7.
#include <stdio.h>
unsigned char i = 0;
int main(void){
for(i = 0;i<=255;i++){
printf("hello world\n");
}

return 0;
}

这个情况与例5相同。

3.浮点数

浮点数我们不做过多说明,详情我们在【C入门到精通】讲过。

我们着重强调一下,对于 2 个浮点数的比较 来说,不能像整型那样直接比较,应该引入一个误差范围,比如:

#define E 1e-4 //定义一个精度

float i = 19.0;
float j = i / 7.0;

if (j * 7.0 - i < E && j * 7.0 - i > -E) {
printf("相等!\n");
} else {
printf("不相等!\n");
}

如果本文你有地方没有看懂,推荐阅读以下文章,可以帮助你理解