0

我的教科书中有一个练习:

int comp(data_t a, data_t b) {
    return a COMP b;
}

显示了参数 a 和 b 之间的一般比较,其中我们可以通过使用 typedef 声明声明 data_t 来设置参数的数据类型,我们可以通过使用 #define 声明定义 COMP 来设置比较。假设 a 在 %edx 中,b 在 %eax 中。对于以下每个指令序列,确定哪些数据类型 data_t (可能有多个正确答案;您应该将它们全部列出。)

cmpl %eax, %edx
setl %al

教科书上的答案是:

后缀“l”和寄存器标识符表示 32 位操作数,而比较是针对二进制补码“<”。我们可以推断出 data_t 必须是 int。

所以我的问题是:既然它要求列出所有可能的答案,为什么 data_t 也不能​​是 'long int' 和也是 32 位的指针?

4

1 回答 1

1

您非常具体的问题的非常具体的答案是因为 long 没有固定的大小定义。当第一个 32 位 x86 处理器问世并开始 16 位到 32 位的转换时,许多编译器的 int 从 16 位更改为 32 位。但是 long int 保持在 32 位。这种情况一直持续到 64 位 x86 处理器问世并且 / 一些流行的编译器将 long 更改为 64 位而 int 保持 32 位。

但是 int 或 long 位的定义是编译器作者的选择,语言规范中使用术语“实现定义”来涵盖这一点。因此,同一编译器的一个编译器或编译器版本很可能解释为 32 位长,而另一个编译器或相同编译器的版本对于同一目标解释为 64 位。这就是 stdint.h 的来源,它有点像 hack,但基于 C 语言的时代和历史以及许多编译器,他们没有太多选择。

现在,如果您进一步举例编译器输出,您可能/将会发现一些编译器使用较大的寄存器 eax/rax 并避免 al/bl ah/bl 操作,这部分与微编码和性能有关。所以 cmpl 和 eax/edx 告诉你故事的开始,直接阅读你的汇编器文档以了解它的汇编语言(汇编语言是由汇编器定义的,工具,而不是芯片/逻辑设计器,尽管它们通常很相似芯片/IP 供应商文档)。然后考虑到一些编译器可以对较小的变量使用相同的特定指令(但当然不是更大)的可能性。

但是这个程序集与提供的 C 代码不匹配,除非 int 的定义是 8 位。教科书暗示int的定义是32位。所以这是一个可怕且非常糟糕的例子。如果教科书的其余部分是这样的,我祝你好运。无论如何,x86 是错误的第一个学习指令集,永远不应该用于教授此类主题。许多/大多数其他人会更好地为您服务。我相信你可能别无选择,所以你的任务要困难得多。

您可以/应该做的是获取该代码,获取您拥有的一个或多个编译器并为 data_t 和 COMP 提供定义,然后看看您得到了什么。C 代码中的 _t 意味着 stdint.h 的知识,因此将这些定义用于您的测试代码和您对该作业的答案。

于 2018-08-22T04:02:12.670 回答