四元运算符和长运算符有啥区别

Posted

技术标签:

【中文标题】四元运算符和长运算符有啥区别【英文标题】:What is the difference between quad operators and long operators四元运算符和长运算符有什么区别 【发布时间】:2015-07-26 08:40:04 【问题描述】:

简单地说, 我有以下代码:

#include <stdio.h>
#define MAXNO 100
void selectionSort(int [], int);
int main() // main.c

int no = 0, i ;
int data[MAXNO] ;
printf("Enter the data, terminate with Ctrl+D\n") ;
while(scanf("%d", &data[no]) != EOF) ++no;
selectionSort(data, no) ;
printf("Data in sorted Order are: ") ;
for(i = 0; i < no; ++i) printf("%d ", data[i]);
putchar('\n') ;
return 0 ;

我在运行时生成了以下汇编代码 cc -S -Wall main.c

    .file   "main.c"
    .section    .rodata
    .align 8
.LC0:
    .string "Enter the data, terminate with Ctrl+D"
.LC1:
    .string "%d"
.LC2:
    .string "Data in sorted Order are: "
.LC3:
    .string "%d "
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $416, %rsp
    movl    $0, -408(%rbp)
    movl    $.LC0, %edi
    call    puts
    jmp .L2
.L3:
    addl    $1, -408(%rbp)
.L2:
    leaq    -400(%rbp), %rax
    movl    -408(%rbp), %edx
    movslq  %edx, %rdx
    salq    $2, %rdx
    addq    %rdx, %rax
    movq    %rax, %rsi
    movl    $.LC1, %edi
    movl    $0, %eax
    call    __isoc99_scanf
    cmpl    $-1, %eax
    jne .L3
    movl    -408(%rbp), %edx
    leaq    -400(%rbp), %rax
    movl    %edx, %esi
    movq    %rax, %rdi
    call    selectionSort
    movl    $.LC2, %edi
    movl    $0, %eax
    call    printf
    movl    $0, -404(%rbp)
    jmp .L4
.L5:
    movl    -404(%rbp), %eax
    cltq
    movl    -400(%rbp,%rax,4), %eax
    movl    %eax, %esi
    movl    $.LC3, %edi
    movl    $0, %eax
    call    printf
    addl    $1, -404(%rbp)
.L4:
    movl    -404(%rbp), %eax
    cmpl    -408(%rbp), %eax
    jl  .L5
    movl    $10, %edi
    call    putchar
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

我不明白的是:

四元运算和长运算(如movqmovl)之间有什么区别。我知道一个用于 64 位,另一个用于 32 位操作,但这里的整数被视为 32 位,对吗?那么为什么在代码中混合了movqs 和movls(或任何其他操作)?

编辑:

忘记添加我的系统的详细信息:

Linux Z510 3.13.0-58-generic #97-Ubuntu SMP Wed Jul 8 02:56:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

【问题讨论】:

存在混合,因为某些操作需要是 64 位的,例如对指针的操作。编译器将根据情况使用正确的操作数大小。 【参考方案1】:

从 C 的角度来看,“Long”或“Integer”值的大小取决于编译器,而不是架构。您可以保证 long C 类型至少与unsigned int 一样长,但除此之外没有其他内容。这就是为什么将位长特定类型添加到 C 标准中的原因,允许您根据需要定义大小。看来您的编译器选择使用 32 位整数。

除此之外,还有对堆栈上值的引用。您正在处理的系统上的堆栈宽度似乎是 64 位,这是有道理的,因为它允许您推送单个寄存器的内容并保持 64 位对齐。

您发布的代码中的结果是您将它们视为四字(32 位),而其他引用(例如内存位置)是 64 位。因此,“quad”字是 32 位移动,long 移动是 64 位值。

【讨论】:

这很有见地。我完全忘记了地址是 64 位的,因为我在 x86_64 架构上。还有两件事:这个汇编代码到底叫什么?我对 MIPS 有一点了解,这似乎具有相似的结构。但每当我想用谷歌搜索任何东西时,我只使用assemblygas,但结果并不具体。我应该寻找什么? - 有什么文档可以指导我了解这段代码的语义吗? @David:“堆栈宽度”不是我以前听过的术语。看起来您的意思是“地址大小”和“堆栈对齐”。另外,第一段有点误导。所有对Cint数据操作的指令都是32位的,因为x86-64 Linux ABI有32位int,64位long。如果编译器编写者想要与同一系统的其他代码兼容,他们就无法选择它。 第三段:在 x86 术语中,一个词是 16 位。 dword 是 32 位,qword 是 64。movl 是 32 位移动,movq 是 64 位移动。 (AT&T 语法 movl 助记符早于 AMD64,所以有点混乱。) @PeterCordes 有关堆栈宽度的示例,请参阅这些问题:***.com/questions/1311740/…***.com/questions/3146582/… @DavidHoelzer:好的,我的立场是正确的。我看到它确实习惯于引用条目的大小,因此是最小对齐。不过,第 3 段中的 32 位 qword 混淆仍然是一个问题。指令上的q 后缀表示64 位,而l 后缀表示32 位。 q 是 amd64 的新成员,l 出现在 x86 中。

以上是关于四元运算符和长运算符有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 中的 != 和 !== 运算符有啥区别?

“++”和“+= 1”运算符有啥区别?

SQL 中的 NOT 和 != 运算符有啥区别?

+=和=+ C赋值运算符有啥区别[重复]

== 运算符和 equals() 有啥区别? (使用哈希码()???)

JavaScript 中 + 运算符和 concat() 方法有啥区别