GCC -O3 6.1.1,5.3.1,4.1.2无法编译正确的可执行文件(C中的递归合并排序)

时间:2016-07-19 11:54:05

标签: c gcc

使用GCC(至少6.1.1,5.3.1,4.1.2)和优化-O3(以及-O2)时,以下程序未编译为正确的可执行文件。 GCC使用-O0(和-O1)生成正确的可执行文件。

输出应为(-O0):

Sorted array: 1.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000 9.00010.0009999.00012.00013.00014.00015.00016.00017.00018.0001                     9.00020.000

代替(-O3):

Sorted array:11.00012.00013.00014.00015.00016.00017.00018.00019.00020.0009999.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000                      9.00010.000

有人知道原因吗?这是GCC的错误吗? 谢谢!

#include <stdio.h>
#include <stdlib.h>

double arr[20] = {20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};

int merge(double arr[],int l,int m,int h)
{
    double arr1[10],arr2[10];
    int n1,n2,i,j,k;

    n1=m-l+1; n2=h-m;
    for(i=0; i<n1; i++) arr1[i]=arr[l+i];
    for(j=0; j<n2; j++) arr2[j]=arr[m+j+1];

    arr1[i]=9999; arr2[j]=9999; i=0; j=0;

    for(k=l; k<=h; k++) {
        if(arr1[i]<=arr2[j])
            arr[k]=arr1[i++];
        else
            arr[k]=arr2[j++];
    }

return 0;
}

int merge_sort(double arr[],int low,int high)
{
    int mid;
    if(low<high) {
        mid=(low+high)/2;
        merge_sort(arr,low,mid);
        merge_sort(arr,mid+1,high);
        merge(arr,low,mid,high);
    }
    return 0;
}

int main()
{
    int i,n=20;

    merge_sort(arr,0,n-1);
    printf("Sorted array:");
    for(i=0; i<n; i++)
        printf("%6.3f",arr[i]);
    printf("\n");

    exit(0);
}

3 个答案:

答案 0 :(得分:2)

(至少)有一个错误。

merge中你有:

double arr1[10],arr2[10];

工作数组需要大一个才能符合监视值(9999),因此您需要:

double arr1[11],arr2[11];

答案 1 :(得分:1)

我在gcc 5.4.0上看到-O0和-O3之间的相同结果:

evaitl@bb ~/se $ gcc -Wall -O0 -o foo foo.c
evaitl@bb ~/se $ ./foo 
Sorted array:11.000  12.000  13.000  14.000  15.000  16.000  17.000  18.000  19.000  20.000  9999.000   2.000   3.000   4.000   5.000   6.000   7.000   8.000   9.000  10.000  
evaitl@bb ~/se $ gcc -Wall -O3 -o foo foo.c
evaitl@bb ~/se $ ./foo 
Sorted array:11.000  12.000  13.000  14.000  15.000  16.000  17.000  18.000  19.000  20.000  9999.000   2.000   3.000   4.000   5.000   6.000   7.000   8.000   9.000  10.000 

当然,算法看起来好像做了一些奇怪的事情,但至少编译器是一致的。

答案 2 :(得分:1)

在断言它是正确的之前检查你自己的代码并责备编译器。 (The first rule of programming: it's always your fault

AddressSanitizer显示问题:

=================================================================
==13359==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff0e9e3f40 at pc 0x000000400c59 bp 0x7fff0e9e3e80 sp 0x7fff0e9e3e70
WRITE of size 8 at 0x7fff0e9e3f40 thread T0
    #0 0x400c58 in merge /tmp/sort.c:15
    #1 0x400f9f in merge_sort /tmp/sort.c:34
    #2 0x400fcc in main /tmp/sort.c:43
    #3 0x7f3d7416857f in __libc_start_main (/lib64/libc.so.6+0x2057f)
    #4 0x400928 in _start (/tmp/a.out+0x400928)

Address 0x7fff0e9e3f40 is located in stack of thread T0 at offset 112 in frame
    #0 0x400a05 in merge /tmp/sort.c:7

  This frame has 2 object(s):
    [32, 112) 'arr1' <== Memory access at offset 112 overflows this variable
    [160, 240) 'arr2'