微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

硬件如何知道一个变量是正数还是负数?

如何解决硬件如何知道一个变量是正数还是负数?

如果这个问题太基础,我很抱歉......我只是没有在任何地方找到答案。

假设我像这样声明了一个 C 变量:

unsigned int var = 241;

在这种情况下,var 是无符号的,所以我的目的是让它具有十进制值 241。

或者我可以这样声明:

signed int var = -15;

在这种情况下,我将其声明为有符号整数,因此根据我的理解,它应该具有十进制值 -15。

但是两次,我都假设 var 将在内存(硬件)中声明,如下所示: 1111 0001。

那么处理器如何知道,在硬件中的最低级别,我打算将其声明为 241 还是 -15? 我知道用于表示负数等的二进制补码表示法,但是,我假设在硬件中,处理器只能看到一系列 1 和 0,然后通过切换某些 IC 的状态对其进行一些操作。处理器如何知道是解释标准二进制(无符号)还是 2 的补码(有符号)中的位序列?

还有一个有点不相关的问题:

  1. 在 C 中,我可以这样做:

    unsigned int var = -15; printf("变量是:%d",var); 这将按预期打印 -15。 为什么,当我这样做时:

有符号整数 var = 0xF1; //或0b11110001 printf("变量是:%d",var);

我得到 241 而不是 -15?既然我声明它是有符号的,并且在二进制补码中 0xF1 是 -15,为什么我得到的值 241 相当于标准二进制中的 0xF1?

  1. 为什么编译器让我做这样的事情: unsigned int var = -15;

它不应该抛出一个错误,告诉我我不能将负值赋给我声明为无符号的变量吗?

谢谢你,我为我的许多可能是基本的问题道歉,我不知道的太多了。

解决方法

硬件不知道。
编译器知道。
编译器知道,因为你在这里说过 signed int var = -15;,“亲爱的编译器,这是一个可以为负的变量,我将其初始化为负值。”
在这里,您换了一种说法 unsigned int var = 241;,“亲爱的编译器,这是一个不能为负的变量,我将其初始化为正值。”

编译器将记住这一点,以便您以后对变量及其值进行任何操作。编译器会将所有相应的代码转换为机器语言中的那组指令,这将导致硬件做出相应的行为。所以硬件最终会做一些适合消极或不适合的事情;不是因为知道,而是因为没有选择。

“相应指令”的一个有趣方面(正如 Peter Cordes 在下面的评论中指出的)是,对于负值的 2 补码表示的特殊(但非常广泛使用)情况,指令实际上是两者相同(这是 2-complement 的一个重要优势)。

,

如果两个值是 char(有符号或无符号),那么它们的内部表示(8 位模式)在内存或寄存器中将是相同的。 唯一的区别在于编译器在处理这些值时发出的指令。 例如,如果这些值存储在 signed 中声明为 unsignedC 的变量中,那么这些值之间的比较将使编译器生成一个 signed无符号汇编级别的特定比较指令。

但在您的示例中,您使用了 int。 假设在您的平台上这些 int 使用四个字节,那么当涉及到它们的 32 位模式时,您提供的两个常量并不相同。 较高位会考虑值的符号并传播以填充 0 或 1 直至 32 位(请参阅下面的 0f 序列)。

请注意,如果您使用正确的编译器标志(例如 unsigned int),则为 -Wconversion 分配负值会在编译时产生警告。 在下面的评论中,@PeterCordes 提醒我们这样的赋值在 C 中是合法的,并且在某些情况下很有用;使用(或不)编译器标志来检测(或不)这种情况只是个人选择的问题。 但是,分配 -15U 而不是 -15 明确表示将常量视为无符号(尽管有减号),并且不会触发警告。

int i1=-15;
int i2=0xF1;
int i3=241;
printf("%.8x %d\n",i1,i1); // fffffff1 -15
printf("%.8x %d\n",i2,i2); // 000000f1 241
printf("%.8x %d\n",i3,i3); // 000000f1 241
unsigned int u1=-15; // warning: unsigned conversion from ‘int’ to ‘unsigned int’ changes value from ‘-15’ to ‘4294967281’
unsigned int u2=0xF1;
unsigned int u3=241;
printf("%.8x %u\n",u1,u1); // fffffff1 4294967281
printf("%.8x %u\n",u2,u2); // 000000f1 241
printf("%.8x %u\n",u3,u3); // 000000f1 241

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。