分段錯誤我花了最近兩天在大型Fortran項目中調試看似無意義的段錯誤。當我將代碼移動到我自己的計算機時,問題就開始了,並且段錯誤出現在一些在多個其他系統上工作良好的代碼中。我最終發現了段錯誤的來源,但它是如此令人驚訝的意外(和編譯器相關),我決定在這裏發佈它。將參數傳遞給子程序
考慮以下MWE:
program dafuq
implicit none
integer :: a=1
integer, parameter :: b=2
call foo(a,b)
end program dafuq
subroutine foo(a,b)
implicit none
integer, intent(inout) :: a, b
a=b !OK
b=a !causes segfault
end subroutine foo
我訪問兩個HPC集羣,這與我的筆記本電腦一起讓我檢查這些(偶爾有點老)編譯器:
- ifort 11.1
- gfortran 4.1.2
- gfortran 4.4.7
- gfortran 4.8.4(最新在回購爲Ubuntu 14.04)
事實證明,所有四個編譯器產生與上面的代碼段錯誤,因爲可變b
被聲明爲parameter
。因此,在子程序中改變它的值是違規的。我的問題是,只有最新的gfortran在編譯時纔會顯示警告(即使使用-Wall),如果我忽略子例程中的intent
規範,這也會消失。我懷疑在C++中使用const
變量的相同設置會引發巨大的紅旗。
現在,使其更加模糊,考慮下面的代碼,用數組來代替標量:
program dafuq_array
implicit none
integer :: a(2)=(/1,1/)
integer, parameter :: b(2)=(/2,2/)
call foo(a,b)
end program dafuq_array
subroutine foo(a,b)
implicit none
integer, intent(inout) :: a(2), b(2)
a=b !OK
b=a !might cause segfault
end subroutine foo
現在,在這種情況下,最新的gfortran產生段錯誤,而其他三個編譯器不要」牛逼! (其實這就是我之前沒有遇到這個問題的原因:列表中最新的gfortran是我自己的計算機上的)。在所有情況下,我基本上都沒有使用編譯開關,即ifort -o mwe mwe.f
,gfortran也是如此。
儘管我找到了段錯誤的原因,並且我對它有所瞭解,但仍有一些錯誤(無意雙關)。
- 我是否錯在期待編譯錯誤/警告在這種情況下?或者至少有一個超出「無效內存引用」的運行時錯誤。
- 使用數組避免某些編譯器出現此錯誤是否有意義?
- 我說得對,在不同系統上遇到的不同行爲是由於編譯器的不同造成的,還是因爲系統特定的細微差別?
感謝您的快速回答。我在開發過程中不時使用'-gen-interfaces -warn interfaces',但是該項目是f77和f90-樣式部分的混合體,大多數舊例程缺少意圖規範。不幸的是,自動接口無法找到這些錯誤沒有意圖。 –