繁体   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)

使用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);
}

(至少)有一个错误。

merge您有:

double arr1[10],arr2[10];

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

double arr1[11],arr2[11];

我在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 

当然,该算法似乎在做奇怪的事情,但至少编译器是一致的。

在断言您的代码正确无误之前,请检查自己的代码并责怪编译器。 编程的第一条规则:总是你的错

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