【问题标题】:How does the computer make the difference between types?计算机如何区分类型?
【发布时间】:2020-01-06 13:53:07
【问题描述】:

我想知道我的计算机如何在完全相同的一组 0 和 1 之间产生差异。我真的不知道应该是什么问题,但我想知道例如当我在 C 中时:

int main(){
   __uint8_t a = 97;
   printf(" Here is a char : %c\n Here is a number : %d\n", a, a);
   return 0;
}

它怎么知道他什么时候应该打印 'a' 或 97。我知道这是由于 %c 和 %d,但到底发生了什么?

谢谢大家!

【问题讨论】:

  • printf 函数的实现决定了如何解释格式字符串和参数。如果您想了解更多详细信息,可以查找printf 函数的源代码。
  • 所以这是我的问题:printf 如何知道如何解释字符串?
  • 某处可能有某种转换表将整数97 转换为字符a。但它不会发生在printf 函数中,而是在将值打印到终端时发生。
  • 就像我说的,如果你想了解它是如何做到的,请查看printf 源代码。
  • 我想更进一步,就二进制代码而言,cpu 确实知道它是一个字符还是一个数字?有一些元数据吗?

标签: c binary cpu computer-science


【解决方案1】:

我想知道我的计算机如何在完全相同的一组 0 和 1 之间产生差异。

在一般情况下,不同的指令以不同的方式解释相同的位序列。例如,x86 ADDL 指令将其操作数解释为 32 位整数值,而 ADDSD 将其操作数解释为标量双精度浮点值。

您在源代码中指定的类型信息(intdoublechar 等)决定了编译器生成哪些机器指令。例如,如果你有代码

double a = 1.0, b = 2.0;
double c = a + b;

编译器会将其翻译成

movsd   -8(%rbp), %xmm0     // move value of a (1.0) to xmm0 register
addsd   -16(%rbp), %xmm0    // add value of b (2.0) to value in xmm0, store result in xmm0
movsd   %xmm0, -24(%rbp)    // copy value in xmm0 (3.0) to c

如果您将double 更改为int

int a = 1, b = 2;
int c = a + b;

然后编译器生成代码:

movl    -4(%rbp), %edx   // move value of a (1) to edx register
movl    -8(%rbp), %eax   // move value of b (2) to eax register
addl    %edx, %eax       // add value in edx to eax, store result in eax
movl    %eax, -12(%rbp)  // copy value in eax to c

不过,对于您的具体问题:

我知道这是由于 %c 和 %d,但究竟发生了什么?

整数 97 存储为位序列 - 假设为 8 位类型,则该位序列为 011000010x61

%c 基本上说“将此值作为基本字符集中的相应符号呈现” - IOW,符号 'a'。某处存在整数值和相应符号之间的映射。

%d 转换说明符基本上是说“创建此值的十进制字符串表示形式”——也就是说,发出 序列 字符{'9', '7'}

值如何映射到字符并显示是实现和终端驱动程序的功能,并且会因系统而异。

【讨论】:

  • 非常感谢!这正是我想要的!我在 ARM 中做了一些汇编语言,所以我对那些寄存器有点困惑
【解决方案2】:

你提到的%c%d称为转换说明符,每一个都有特定的含义。它们预先决定了如何处理、格式化和打印相应的参数。

引自C11,第 7.21.6.1 章,一些示例:

  1. 转换说明符及其含义是:

d,i int 参数以 [−]dddd 样式转换为有符号十进制。

c 如果不存在 l 长度修饰符,则 int 参数将转换为 unsigned char,然后写入生成的字符。

这样,每个转换说明符都有相关的规则,说明它们如何解释和打印提供的参数或忽略它们(例如:%%)。

【讨论】:

  • 谢谢先生,那么我在哪里可以找到处理、格式化和打印参数的位置?因为在printf的源码中,并没有出现这种情况
  • @EliasEl 在哪里或如何?如果您问的是“哪里”:请查看 printf 的 man page 了解详细信息。
  • 所以现在我会问:如何?
  • @EliasEl 不确定您查看的是什么来源,但printf 的来源肯定会在某个时候处理参数和格式。现在printf 可能会调用另一个函数来处理一些详细的工作,因此您需要追踪printf 可能调用的任何函数的源代码。但这一切都在那里。
【解决方案3】:

当您要求使用 %c 进行打印时,计算机将查看 ASCII 表。计算机只能理解数字(二进制​​),此表是如何将数字更改为字符的参考(见下文),因为您可以看到十进制的 a = 97 等于二进制的 0110 0001。在代码中,您可以要求以不同的格式显示一个值(%d 表示十进制,%f 表示浮点数,%c 表示字符 ...)但它在计算机中始终是二进制字

如果您想了解有关低硬件层的更多信息,请询问我

【讨论】:

    【解决方案4】:

    计算机不知道。你通过%c%dprintf 格式字符串中告诉他。

    在这个特殊的架构中使用 ASCII 码是一个约定,其中 97 是a

    您可以使用您喜欢的任何编码编写自己的输出函数。

    【讨论】:

      猜你喜欢
      • 2010-10-06
      • 2017-01-26
      • 2018-10-07
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多