鱼C论坛

 找回密码
 立即注册
查看: 985|回复: 6

[已解决]s1e39课上程序测试题六

[复制链接]
发表于 2023-6-9 20:29:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 houqing1999 于 2023-6-9 20:42 编辑

如下标黄的四个疑惑,谢谢。
我测了一下Visual Studio是小端字节序,详情见https://fishc.com.cn/thread-75394-1-1.html,但运行之后提示如图其一请问这个是什么意思 微信图片_20230609201500.png
#include <stdio.h>

int main(void)
{
        char a = 0, b = 0;
        int *p = (int *)&b;//其二,此外此代码的含义是我理解的把b的地址赋给指针p并强制装换成整形吗,由于局部变量a,b地址连续(其三,只要连续定义两个局部变量地址就一定连续吗)并且b在前,所以这导致b强制转换后污染了a的地址。

        *p = 258;

        printf("%d %d\n", a, b);

        return 0;
}

运行后a,b的结果也不像理想的用VirtualBox虚拟机Linux运行的结果如图 173121qsrsimb23ffq3imr.png 而是 微信图片_20230609201505.png
是什么原因,其四。
最佳答案
2023-6-9 20:33:01

此程序设计来测试你的机器是否是小端方式(Little-endian)还是大端方式(Big-endian)。这两种方式是处理器存储和读取多字节数据(比如int类型、float类型等)的方式。

其一:这个提示可能是因为你的代码产生了未定义行为。你试图将一个char变量的地址强制转化为一个int指针,这在C标准中是不被允许的,会导致未定义行为。而"未定义行为"是指,该行为在C标准中没有明确规定,不同的编译器可能会有不同的处理方式。

其二:你的理解是正确的。你的代码确实是把变量b的地址赋给指针p,并强制转换为int*类型。然而,如我在其一中所述,这是一种未定义行为。

其三:局部变量在栈上连续分配的这个行为也是没有明确规定的。C标准没有明确规定局部变量在内存中的布局,虽然许多编译器都会按顺序在栈上分配它们,但这并非一定。因此,不能肯定的说两个连续定义的局部变量的地址就一定连续。

最后的问题:结果与预期不符是因为你在使用一个int指针修改一个char变量,而这两个类型的大小是不一致的。在大多数现代处理器上,char是8位,而int是32位。你试图用一个32位的int来修改一个8位的char,这导致了溢出,你实际上修改了两个char变量a和b的值。

总结,你在此程序中试图做一些未在C标准中明确定义的事情,这导致了不可预测的结果。如果你想探索处理器的字节顺序,我建议你使用更安全、更明确的方式,比如使用联合体(union)。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-6-9 20:29:45 | 显示全部楼层

回帖奖励 +20 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-6-9 20:32:24 | 显示全部楼层

期待您的解答
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-9 20:33:01 | 显示全部楼层    本楼为最佳答案   

此程序设计来测试你的机器是否是小端方式(Little-endian)还是大端方式(Big-endian)。这两种方式是处理器存储和读取多字节数据(比如int类型、float类型等)的方式。

其一:这个提示可能是因为你的代码产生了未定义行为。你试图将一个char变量的地址强制转化为一个int指针,这在C标准中是不被允许的,会导致未定义行为。而"未定义行为"是指,该行为在C标准中没有明确规定,不同的编译器可能会有不同的处理方式。

其二:你的理解是正确的。你的代码确实是把变量b的地址赋给指针p,并强制转换为int*类型。然而,如我在其一中所述,这是一种未定义行为。

其三:局部变量在栈上连续分配的这个行为也是没有明确规定的。C标准没有明确规定局部变量在内存中的布局,虽然许多编译器都会按顺序在栈上分配它们,但这并非一定。因此,不能肯定的说两个连续定义的局部变量的地址就一定连续。

最后的问题:结果与预期不符是因为你在使用一个int指针修改一个char变量,而这两个类型的大小是不一致的。在大多数现代处理器上,char是8位,而int是32位。你试图用一个32位的int来修改一个8位的char,这导致了溢出,你实际上修改了两个char变量a和b的值。

总结,你在此程序中试图做一些未在C标准中明确定义的事情,这导致了不可预测的结果。如果你想探索处理器的字节顺序,我建议你使用更安全、更明确的方式,比如使用联合体(union)。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-9 20:45:33 | 显示全部楼层
本帖最后由 houqing1999 于 2023-6-9 20:49 编辑
isdkz 发表于 2023-6-9 20:33
此程序设计来测试你的机器是否是小端方式(Little-endian)还是大端方式(Big-endian)。这两种方式是处 ...


原题是这样的
微信图片_20230609204433.png 微信图片_20230609204429.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-9 20:54:17 | 显示全部楼层
isdkz 发表于 2023-6-9 20:33
此程序设计来测试你的机器是否是小端方式(Little-endian)还是大端方式(Big-endian)。这两种方式是处 ...

您最好了,那么我接受您的建议,请问怎样用联合体探索处理器的字节顺序
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-9 20:57:09 | 显示全部楼层
houqing1999 发表于 2023-6-9 20:54
您最好了,那么我接受您的建议,请问怎样用联合体探索处理器的字节顺序

在C语言中,联合体(union)可以让我们在同一段内存空间上存储不同类型的变量,因此我们可以利用这个特性来探索机器的字节顺序。具体的方法是,我们先用一个int型的变量存储一个值,然后用一个char型的变量去读取这个int型变量的第一个字节,从而确定机器的字节顺序。

这是一个例子:
#include <stdio.h>

union ByteOrder {
    int value;
    char firstByte;
};

int main() {
    union ByteOrder test;
    test.value = 1;
    
    if (test.firstByte == 1) {
        printf("Little endian\n");
    } else {
        printf("Big endian\n");
    }
    
    return 0;
}

在这个例子中,我们首先创建了一个名为ByteOrder的联合体,这个联合体有两个成员:一个是int型的value,另一个是char型的firstByte。在main函数中,我们创建了一个ByteOrder型的变量test,并将它的value设置为1。由于value和firstByte共享内存空间,因此当我们读取firstByte的时候,我们实际上是在读取value的第一个字节。在小端方式中,最低有效位(即1所在的位置)存储在最小的地址中,因此firstByte的值会是1;在大端方式中,最低有效位存储在最大的地址中,因此firstByte的值会是0。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-28 01:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表