自上篇文章所述在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}VisualCWin32Debug
21 ${SDL2_ROOT}VisualCWin32Release
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}VisualCWin32Debug
- “配置”:”Release”--->“”链接器“--->”常规”--->”附加库目录“: ${SDL2_ROOT}VisualCWin32Release
- 拷贝对应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()函数?