看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《ddv70 (心神合一)》之銘言: : 完整錯誤訊息: : runtime error! : program:C:(程式路徑) : R6030 : -CRT not initialialized 原發問者提供的資訊不足。單純就錯誤訊息本身的含義來討論。 CRT not initialialized: 也就是 Microsoft C-RunTime 函式庫,未初始化。 可能是有執行 CRT,但過程中出錯,這種機率比較小;也可能是根本沒有執行到 CRT。 簡單的問題重現方式: /* 檔案名稱:r6030.c */ #include <stdio.h> #include <stdlib.h> int main() { int *ptr = 0; ptr = malloc(1024); ptr[0] = 1; return 0; } 啟動 Visual Studio 命令提示字元 (2010),執行 編譯連結指令 cl.exe r6030.c /Zi /link /entry:main 再啟動 r6030.exe: runtime error R6030 - CRT not initialized 上述指令中 /Zi 只是為了輸出 *.pdb 檔來方便偵錯。而 /link /entry:main 是強迫更改 程式啟動後執行的第一個函數 (entry point), 從 mainCRTStartup 函數修改成 main 函數。 由 Visual Studio 附的 VC 原始碼 malloc.c 中,可知此函數: __forceinline void * __cdecl _heap_alloc (size_t size) { if (_crtheap == 0) { _FF_MSGBANNER(); /* write run-time error banner */ _NMSG_WRITE(_RT_CRT_NOTINIT); /* write message */ __crtExitProcess(255); /* normally _exit(255) */ } return HeapAlloc(_crtheap, 0, size ? size : 1); } 在檔案 rterr.h 及 cmsgs.h 可知有以下定義: #define _RT_CRT_NOTINIT 30 /* CRT is not initialized */ #define _RT_CRT_NOTINIT_TXT L"R6030" EOL L"- CRT not initialized" EOL 在檔案 heapinit.c 可知有以下全域變數: HANDLE _crtheap=NULL; /* NULL is 0 */ 因為 VC 會連結 heapinit.c 與 r6030.c 這兩者的目的檔 (*.obj), 所以 _crtheap 必然初始值為 0,直到 CRT 的初始化正確進行才會變成非 0 值。 可是 r6030.exe 的入口點,是直接進入 main(),沒有先通過 mainCRTStartup() 函數, 就沒有做 CRT 初始化,所以 _crtheap 保留初始值。 所以當 r6030.exe 執行到 ptr = malloc(1024); 時,會接著進入 _heap_alloc(), 然後輸出錯誤訊息 "R6030\n- CRT not initialized\n", 然後執行 __crtExitProcess(255); 強制中斷程式運行,然後就沒有然後了。 ---- 補充: 上面的 return HeapAlloc(_crtheap, 0, size ? size : 1); 按照我上篇發文中討論的優先權議題,將等價於: return HeapAlloc( _crtheap, 0, (size ? size : 1) ); /* 所以 malloc(0); 等價於 malloc(1); */ 因為 _crtheap, 0, size 構成的是 expression 不能當作 ?: 的運算元I,所以運算元I 只會是 size。 要注意的是,在上面的 () 小括號中間出現的 , 其實不是真的 comma 運算子, 那只是分隔 HeapAlloc 的三個 arguments 用的逗號。 因為根據此文 http://en.wikipedia.org/wiki/Sequence_point Note that a function call f(a,b,c) is not a use of the comma operator and the order of evaluation for a, b, and c is unspecified. 如果 f() 中出現的逗號是 comma 運算子的話,會變成 a 要先運算完畢,把 副作用全部消除,才接著進行 b 的運算,事實上不是。 這部份有點算是特例,麻煩。應該不要在函數呼叫的小括號內: (1) 使用 comma 運算子 /* 當然 comma 運算子本來就很少使用 */ (2) 放入任何會產生副作用的運算式,比如拿 a++ 當 arg1,又拿 a 當 arg2 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 124.8.130.63
ddv70:謝謝講解,但我原先這隻程式可以在桌機上正常執行 03/05 14:37
ddv70:但換到筆記型電腦後就不行,一執行exe檔就跳出上續訊息 03/05 14:38
ddv70:看完大大的講解我還是不太知道怎麼更改才好 03/05 14:38