簡體   English   中英

程序員的錯誤或gcc-5.1.0錯誤?

[英]Programmer's error or gcc-5.1.0 bug?

我嘗試使用帶有優化標志-O1 / -O2 / -O3 / -Og的gcc-5.1.0編譯一大塊軟件。 它給了我警告-Wmaybe-uninitialized-Wuninitialized並在運行時失敗。 調試后我找到了導致它的代碼,但是我無法理解為什么。 我減少了代碼以重現失敗:

#include <cstdlib>
#include <iostream>

template<class T>
struct foo {
    template<class U>
    char bar(const U &x) {
        //return id(x)[0];
        const T &y = id(x);
        return y[0];
    }

    const T &id(const T &elem) {
        return elem;
    }
};

int main(void) {
    foo<const char *> f;
    char *str = "hello world";
    //std::cout << f.bar((const char *)str) << std::endl;
    std::cout << f.bar(str) << std::endl;
    return 0;
}

gcc-5.1.0給出以下警告:

g++ -Og -Wall -Wextra -Wno-write-strings    test.cpp   -o test
test.cpp: In function ‘int main()’:
test.cpp:10:19: warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]
         return y[0];
                   ^
test.cpp:9:24: note: ‘<anonymous>’ was declared here
         const T &y = id(x);
                        ^

該程序在運行時收到SIGSEGV並崩潰。 由於優化很難調試,但在使用代碼后我認為問題是const T &y = id(x); y分配NULL (通過替換return y[0];使用只返回y[0]函數調用。)我目前無法使用其他版本的gcc測試代碼,但是派生示例的代碼在用gcc-4.9.2編譯。 當與clang-3.6.1混合使用時,它也適用於任何優化級別。 我的下一步是試圖弄清楚導致它的確切優化是什么,所以我在makefile中放入了我能夠找到的所有gcc的優化標志,但它在沒有警告的情況下編譯,並且在運行時不會崩潰。

我的問題是:

  • 它是正確的C ++代碼嗎?
  • 它是gcc-5.1.0中的已知/未知錯誤嗎?
  • 我是否正確理解,在上面的例子中T = [const char *]; U = [char *] T = [const char *]; U = [char *] ,當我寫const T &y = id(x); 應該將xchar *隱式轉換為const char *y是對const char *的常量引用?
  • 如果模板錯誤,那么確切的錯誤是什么?
  • 如何弄清楚導致它的確切優化標志是什么?

注意:取消注釋任何注釋行可修復程序。

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /build/gcc-multilib/src/gcc-5-20150623/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --with-default-libstdcxx-abi=c++98
Thread model: posix
gcc version 5.1.0 (GCC)

gcc的優化標志我嘗試過:

-falign-functions -falign-jumps -falign-labels -falign-loops -fassociative-math
-fauto-inc-dec -fbranch-count-reg -fbranch-probabilities -fbranch-target-load-optimize
-fbranch-target-load-optimize2 -fbtr-bb-exclusive -fcaller-saves -fcheck-data-deps -fcheck-new
-fcombine-stack-adjustments -fcompare-elim -fconserve-stack -fcprop-registers -fcrossjumping
-fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules -fcx-limited-range -fdata-sections
-fdce -fdefer-pop -fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively
-fdse -fearly-inlining -fexpensive-optimizations -fext-numeric-literals -ffast-math
-ffinite-math-only -ffloat-store -ffor-scope -fforward-propagate -ffriend-injection
-ffunction-sections -fgcse -fgcse-after-reload -fgcse-las -fgcse-lm -fgcse-sm -fguess-branch-probability
-fhoist-adjacent-loads -fif-conversion -fif-conversion2 -findirect-inlining -finline-functions
-finline-functions-called-once -finline-small-functions -fipa-cp -fipa-cp-alignment -fipa-cp-clone
-fipa-icf -fipa-matrix-reorg -fipa-profile -fipa-pta -fipa-pure-const -fipa-ra -fipa-reference
-fipa-sra -fipa-struct-reorg -fisolate-erroneous-paths-dereference -fivopts -fkeep-inline-functions
-fkeep-static-consts -floop-block -floop-interchange -floop-strip-mine -flra-remat -fmerge-all-constants
-fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves -fmove-loop-invariants -fms-extensions
-fnothrow-opt -fomit-frame-pointer -foptimize-register-move -foptimize-sibling-calls -foptimize-strlen
-fpartial-inlining -fpeel-loops -fpeephole2 -fpermissive -fpredictive-commoning -fprefetch-loop-arrays
-fprofile-correction -fprofile-generate -fprofile-use -fprofile-values -freciprocal-math -fregmove
-frename-registers -freorder-blocks -freorder-blocks-and-partition -freorder-functions -frerun-cse-after-loop
-freschedule-modulo-scheduled-loops -frounding-math -fsched-interblock -fsched-spec -fsched-spec-load
-fsched-spec-load-dangerous -fsched-stalled-insns -fsched-stalled-insns-dep -fsched2-use-superblocks
-fsched2-use-traces -fschedule-insns -fschedule-insns2 -fsee -fsel-sched-pipelining
-fsel-sched-pipelining-outer-loops -fselective-scheduling -fselective-scheduling2 -fshrink-wrap
-fsignaling-nans -fsingle-precision-constant -fsized-deallocation -fsplit-ivs-in-unroller
-fsplit-wide-types -fssa-phiopt -fstack-protector -fstack-protector-all -fstrict-aliasing
-fstrict-overflow -fthread-jumps -ftracer -ftree-bit-ccp -ftree-builtin-call-dce -ftree-ccp
-ftree-ch -ftree-coalesce-vars -ftree-copy-prop -ftree-copyrename -ftree-dce -ftree-dominator-opts
-ftree-dse -ftree-forwprop -ftree-fre -ftree-loop-distribute-patterns -ftree-loop-distribution
-ftree-loop-im -ftree-loop-ivcanon -ftree-loop-linear -ftree-loop-optimize -ftree-loop-vectorize
-ftree-partial-pre -ftree-phiprop -ftree-pre -ftree-pta -ftree-reassoc -ftree-sink -ftree-slp-vectorize
-ftree-slsr -ftree-sra -ftree-switch-conversion -ftree-tail-merge -ftree-ter -ftree-vect-loop-version
-ftree-vectorize -ftree-vrp -funit-at-a-time -funroll-all-loops -funroll-loops -funsafe-loop-optimizations
-funsafe-math-optimizations -funswitch-loops -fuse-cxa-atexit -fvariable-expansion-in-unroller
-fvect-cost-model -fvisibility-inlines-hidden -fvisibility-ms-compat -fvpt -fvtv-counts -fvtv-debug
-fweb -fwhole-program

您的字符串文字(非法)綁定到char*

char *str = "hello world";

這是C的剩余轉換,自C ++ 98(或C ++ 03?)以來已被棄用,並已在C ++ 11中刪除。 gcc仍然允許它作為擴展,就像clang ++一樣。

當你調用f.bar(str) ,它會推導出U == char* ,因此它的函數參數類型變為char* const&

using U = char*;
template<>
char bar(const U &x) { // char* const& x
    const T &y = id(x);
    return y[0];
}

但是,您已使用模板參數char const*實例化f ,因此id的函數參數類型為char const* const&

const T &id(const T &elem) { // char const* const& elem
    return elem;
}

因此, bar的表達式id(x)必須從char*轉換為char const* ,這將創建一個臨時的。 這個臨時持續到完整表達式const T& y = id(x);的結尾const T& y = id(x); ,因此創建一個懸掛參考y


基本上,您的一個假設是不正確/不完整的:

我是否正確理解,在上面的例子中T = [const char*]; U = [char *] T = [const char*]; U = [char *] ,當我寫const T &y = id(x); 應該將xchar *隱式轉換為const char *y是對const char *的常量引用?

T const*T*類型不是參考兼容的。 有關詳細信息,請參閱[dcl.init.ref]。 但是, T*可以轉換為T const* ,因此創建臨時值並綁定到T const*& 這類似於:

int i = 42;
double const& d = i; // creates a temporary double and binds it to d

這是所有引用不兼容類型的行為,其中源可隱式轉換為目標類型(保存具有轉換函數/運算符的類類型)。

為什么T const*T*不參考兼容? 同樣的推理適用於T const** vs T** ,它們也是不兼容的。 這可以防止出現細微錯誤,請參閱https://stackoverflow.com/a/2908332/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM