2014-11-03 94 views
1

对于使用内联汇编块对数组进行排序的c代码,存在问题。(+ r)与(= r)的约束

我完整的代码是这样的:

#include <stdio.h> 
#define n 20 

int main() 
{ 
    int array[n]; 
    int i; 
    int swapped; 

    printf("Enter the elements one by one \n"); 
    for (i = 0; i < n; i++) 
    { 
     scanf("%d", &array[i]); 
    } 

    printf("Input array elements \n"); 
    for (i = 0; i < n ; i++) 
    { 
     printf("%d\n", array[i]); 
    } 

    /* Bubble sorting begins */ 
    do 
    { 
      swapped = 0; 
      for (i = 1; i < n; i++) 
      { 
/* 
      if (array[i] < array [i-1]) 
      { 
       swapped =1; 
       int temp = array [i-1]; 
       array [i-1] = array [i]; 
       array[i] = temp; 
      } 
*/ 

       //body of the for loop 
       //converted to assembly 
       __asm__ __volatile__("cmp %0, %1;" 
            "jge DONE;" 
            "mov eax, %0;" 
            "mov %0, %1;" 
            "mov %1, eax;" 
            "mov %2, 1;" 
            "DONE: " 
            : "+r" (array[i]), "+r" (array[i-1]), "=r" (swapped) 
            : //no input 
            : "eax", "cc" 
            ); 


      } 

    } while (swapped > 0); 

    printf("Sorted array is...\n"); 
    for (i = 0; i < n; i++) 
    { 
     printf("%d\n", array[i]); 
    } 

    return 0; 
} 

出于某种原因,这样做的同时将成为无限循环,但是当我更改修改为swapped变量"+r" (swapped)它的工作原理。我查看了两种情况下生成的汇编代码(-save-temp),除了在预期使用“+ r”的情况下将swapped变量移动到寄存器外,没有注意到任何其他内容。

为什么我需要使用"+r"

+0

我会害怕写那样的跳跃。想象一下,编译器展开循环,这将跳到哪里?另外,为什么要为此写入内联asm?编译器应该从C代码中更好地生成。 – 2014-11-03 20:15:59

+0

你正在编译'-masm = intel'吗?我看不到你的命令行。 – 2014-11-03 20:29:07

+0

那么,我唯一的目的就是学习GCC内联汇编。此外,我用__volatile__编译-O0代码,只是为了防止这些类型的优化。 – soofyaan 2014-11-03 20:30:29

回答

1

如果你使用=这意味着它是一个输出,它必须被写入。但是,只有在交换时才写。编译器会优化掉你使用的swapped = 0,因为它假设汇编器模块会产生一个新的值来覆盖它。这意味着,如果没有交换,编译器会愉快地使用它为%2选择的寄存器中的任何垃圾,作为swapped的新值,并且偶然地产生无限循环。

下面是一些代码来说明:

swapped = 0; 
/* this is the asm block */ 
{ 
    /* this is not initialized, because it's declared as output */ 
    int register_for_operand2; 
    if (array[i] < array[i - 1]) 
    { 
     /* body here */ 
     register_for_operand2 = 1; 
    } 
    /* the compiler generates this code for the output operand */ 
    /* this will copy uninitialized value if the above condition was false */ 
    swapped = register_for_operand2; 
} 
+0

正确。我只是想出了答案,并准备发布答案。谢谢! – soofyaan 2014-11-03 20:32:29

+0

试图调试它时,我意识到了一个奇怪的行为。如果我把一个printf(“\ n”);代码仍然工作“= r”(交换);就在评估一段时间的情况之前。只是好奇想知道为什么? – soofyaan 2014-11-03 20:35:32

+1

正如小丑所说,它将使用寄存器中的“垃圾”。很明显,printf是(只是偶然)离开你想要的值。显然不是你想要依靠的行为... – 2014-11-03 20:45:23