简体   繁体   English

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

[英]GCC -O3 6.1.1, 5.3.1, 4.1.2 fails to compile a correct executable (recursive merge sort in C)

The following program is not compiled into a correct executable when using GCC (at least 6.1.1, 5.3.1, 4.1.2) and with optimization -O3 (and also -O2). 使用GCC(至少6.1.1、5.3.1、4.1.2)和优化-O3(以及-O2)时,以下程序未编译为正确的可执行文件。 GCC generates a correct executable with -O0 (and -O1). GCC使用-O0(和-O1)生成正确的可执行文件。

The output should be (-O0): 输出应为(-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

instead of (-O3): 而不是(-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

Has anybody an idea of the reason? 有人知道原因吗? Is it a bug of GCC? 这是GCC的错误吗? Thanks! 谢谢!


#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);
}

There is (at least) one bug. (至少)有一个错误。

In merge you have: merge您有:

double arr1[10],arr2[10];

The work arrays needs to be one larger to fit the watch value ( 9999 ), so you need: 工作数组需要大一个以适合监视值( 9999 ),因此您需要:

double arr1[11],arr2[11];

I see identical results between -O0 and -O3 on gcc 5.4.0: 我在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 

Of course, the algorithm seems like it is doing strange things, but at least the compiler is consistent. 当然,该算法似乎在做奇怪的事情,但至少编译器是一致的。

Check your own code before you assert it is correct and blame the compiler. 在断言您的代码正确无误之前,请检查自己的代码并责怪编译器。 ( The first rule of programming: it's always your fault ) 编程的第一条规则:总是你的错

AddressSanitizer shows the problem: 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'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM