自上篇文章所述在VS C++生成SDL2庫文件,編寫簡單Hello World程序驗證庫文件。
1、使用Visual Studio 2019 創建一個終端控制台程序。
點擊“文件—新建—項目”,選擇“控制台應用”,輸入源代碼:
test.cpp:
1 #include <iostream>
2 #include <SDL.h>
3
4 /*
5 * Lesson 0: Test to make sure SDL is setup properly 6 */
7 int main(int, char**) { 8 if (SDL_Init(SDL_INIT_VIDEO) != 0) { 9 std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl; 10 return 1; 11 } 12 std::cout << "SDL_Init OK!!!" << std::endl; 13 SDL_Quit(); 14
15 return 0; 16 } 17
18 /*
19 ${SDL2_ROOT}\include 20 ${SDL2_ROOT}\VisualC\Win32\Debug 21 ${SDL2_ROOT}\VisualC\Win32\Release 22 SDL2.lib 23 SDL2main.lib 24 */
2、設置庫文件目錄、依賴項目錄、依賴項文件名。
點擊菜單“項目“--->"屬性”,在“配置”欄中的“所有配置”適合debug和release都相同的設置,不相同設置單獨選擇”debug”或”release”配置。上述代碼中的${SDL2_ROOT} 替換為你本機實際目錄。
- “配置”:“所有配置”--->“C/C++”--->“常規”--->“附加包含目錄” :${SDL2_ROOT}\include
- “配置”:“所有配置”--->“”鏈接器“--->”輸入“--->”附加依賴項“: SDL2.lib、SDL2main.lib
- “配置”:”Debug”--->“”鏈接器“--->”常規”--->”附加庫目錄“: ${SDL2_ROOT}\VisualC\Win32\Debug
- “配置”:”Release”--->“”鏈接器“--->”常規”--->”附加庫目錄“: ${SDL2_ROOT}\VisualC\Win32\Release
- 拷貝對應debug/release版本的SDL2.dll到對應EXE輸出目錄。
執行程序輸出結果,如圖:

3、補充說明:SDL2入口點函數(入口點符號)。

Test.cpp::main() 中"main"已在頭文件SDL_main.h中定義為宏,跟蹤宏生效的依賴關系如下 :
main ---> SDL_main.h::109 ---> SDL_main.h::40 SDL_MAIN_AVAILABLE ---> SDL_main.h::40 __WIN32__ ---> SDL_platform.h::153 __WINDOWS__ ---> SDL_platform.h::149 WINAPI_FAMILY_WINRT ---> SDL_platform.h:: 139 ---> (…)
Test.cpp 中"main"最終只會有兩種結果,而此示例代碼經過預處理后進行編譯前函數名實際為:SDL_main 。
條件==true ---> SDL_main()
條件==false ---> main()
Test.cpp::main()不是程序的入口點函數,這是因WINDOWS平台C++程序對真實第一個入口點函數有定義,微軟官方文檔說明鏈接如下:
https://docs.microsoft.com/zh-cn/cpp/build/reference/entry-entry-point-symbol?view=vs-2019

由此可見,可分三種情況有三類真正的程序第一個入口函數,再經過固定流程調用指定函數。通過調試本示例分析,得到調用Test.cpp::main() 的函數在SDL_windows_main.c文件,而SDL_windows_main.c::19 執行undef main。

SDL_windows_main.c源代碼文件如下:
1 /* Pop up an out of memory message, returns to Windows */ 2 static BOOL 3 OutOfMemory(void) 4 { 5 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL); 6 return FALSE; 7 } 8 9 #if defined(_MSC_VER) 10 /* The VC++ compiler needs main/wmain defined */ 11 # define console_ansi_main main 12 # if UNICODE 13 # define console_wmain wmain 14 # endif 15 #endif 16 17 /* Gets the arguments with GetCommandLine, converts them to argc and argv 18 and calls SDL_main */ 19 static int 20 main_getcmdline(void) 21 { 22 LPWSTR *argvw; 23 char **argv; 24 int i, argc, result; 25 26 argvw = CommandLineToArgvW(GetCommandLineW(), &argc); 27 if (argvw == NULL) { 28 return OutOfMemory(); 29 } 30 31 /* Parse it into argv and argc */ 32 argv = (char **)SDL_calloc(argc + 1, sizeof(*argv)); 33 if (!argv) { 34 return OutOfMemory(); 35 } 36 for (i = 0; i < argc; ++i) { 37 argv[i] = WIN_WStringToUTF8(argvw[i]); 38 if (!argv[i]) { 39 return OutOfMemory(); 40 } 41 } 42 argv[i] = NULL; 43 LocalFree(argvw); 44 45 SDL_SetMainReady(); 46 47 /* Run the application main() code */ 48 result = SDL_main(argc, argv); 49 50 /* Free argv, to avoid memory leak */ 51 for (i = 0; i < argc; ++i) { 52 SDL_free(argv[i]); 53 } 54 SDL_free(argv); 55 56 return result; 57 } 58 59 /* This is where execution begins [console apps, ansi] */ 60 int 61 console_ansi_main(int argc, char *argv[]) 62 { 63 return main_getcmdline(); 64 } 65 66 67 #if UNICODE 68 /* This is where execution begins [console apps, unicode] */ 69 int 70 console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp) 71 { 72 return main_getcmdline(); 73 } 74 #endif 75 76 /* This is where execution begins [windowed apps] */ 77 int WINAPI 78 WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) 79 { 80 return main_getcmdline(); 81 } 82 83 #endif /* __WIN32__ */ 84 85 /* vi: set ts=4 sw=4 expandtab: */
SDL_windows_main.c源代碼經過預處理后,如下:
1 static BOOL 2 OutOfMemory(void) 3 { 4 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", ((void *)0)); 5 return 0; 6 } 7 8 static int 9 main_getcmdline(void) 10 { 11 LPWSTR *argvw; 12 char **argv; 13 int i, argc, result; 14 argvw = CommandLineToArgvW(GetCommandLineW(), &argc); 15 if (argvw == ((void *)0)) { 16 return OutOfMemory(); 17 } 18 argv = (char **)SDL_calloc(argc + 1, sizeof(*argv)); 19 if (!argv) { 20 return OutOfMemory(); 21 } 22 for (i = 0; i < argc; ++i) { 23 argv[i] = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(argvw[i]), (SDL_wcslen(argvw[i])+1)*sizeof(WCHAR)); 24 if (!argv[i]) { 25 return OutOfMemory(); 26 } 27 } 28 argv[i] = ((void *)0); 29 LocalFree(argvw); 30 SDL_SetMainReady(); 31 result = SDL_main(argc, argv); 32 for (i = 0; i < argc; ++i) { 33 SDL_free(argv[i]); 34 } 35 SDL_free(argv); 36 return result; 37 } 38 int 39 main(int argc, char *argv[]) 40 { 41 return main_getcmdline(); 42 } 43 int 44 wmain(int argc, wchar_t *wargv[], wchar_t *wenvp) 45 { 46 return main_getcmdline(); 47 } 48 49 int __stdcall 50 WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) 51 { 52 return main_getcmdline(); 53 }
經過以上分析后,大家有進一步理解了,本示例代碼是在WINDOWS平台下創建為控制台程序,程序是怎樣從入口點函數調用到應用層的Test.cpp::main()函數?
