💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 33.13\. C++应用程序 ECPG对C++应用程序有一些有限的支持。本节介绍一些注意事项。 `ecpg`预处理程序采取写入C(或者类似C)的输入文件,并且 嵌入SQL命令,将嵌入SQL命令转换为C语言块, 最后生成`.c`文件。 当在C++中使用时, 通过`ecpg`产生的C语言块使用的库函数的头文件声明 被包裹在`extern "C" { ... }`块中。 因此他们应该在C++中无缝工作。 一般情况下,然而,`ecpg`预处理器仅仅了解C;它 不处理特殊语法并且保留C++语言关键字。因此, 写入使用复杂特定C++功能的C++应用程序代码的一些嵌入SQL代码可能 不能正确地被预处理或者可能不会按预期的工作。 在C++应用程序中使用嵌入SQL代码的安全方式是在C模块中隐藏ECPG调用, 其中C++应用程序代码调用访问数据库,并且连同C++代码其余部分一起连接。 参阅[Section 33.13.2](#calibre_link-2016)获取关于它的更多信息。 ## 33.13.1\. 宿主变量范围 `ecpg`预处理器理解C中变量范围。在C语言中, 这是简单地因为变量范围基于他们的代码块。在C++中, 然而,类成员变量参考来自声明位置的不同代码块。 因此`ecpg`预处理程序不理解类成员变量的范围。 比如,在下面情况下,`ecpg`预处理器无法找到 `test`方法中变量`dbname`的任何声明, 因此产生错误。 ``` class TestCpp { EXEC SQL BEGIN DECLARE SECTION; char dbname[1024]; EXEC SQL END DECLARE SECTION; public: TestCpp(); void test(); ~TestCpp(); }; TestCpp::TestCpp() { EXEC SQL CONNECT TO testdb1; } void Test::test() { EXEC SQL SELECT current_database() INTO :dbname; printf("current_database = %s\n", dbname); } TestCpp::~TestCpp() { EXEC SQL DISCONNECT ALL; } ``` 这个代码将产生类似这样的错误。 ``` <kbd class="literal">ecpg test_cpp.pgc</kbd> test_cpp.pgc:28: ERROR: variable "dbname" is not declared ``` 为了避免这个范围问题,`test`方法可以改为使用局部变量作为 中间存储器。但是这个方法仅仅是一个低劣的解决办法,因为 它丑化代码并且降低性能。 ``` void TestCpp::test() { EXEC SQL BEGIN DECLARE SECTION; char tmp[1024]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT current_database() INTO :tmp; strlcpy(dbname, tmp, sizeof(tmp)); printf("current_database = %s\n", dbname); } ``` ## 33.13.2\. C++应用程序开发与外部C模块 如果你理解C++中`ecpg`预处理器的这些技术局限性, 你可能得到这样的结论在链接阶段链接中C对象与C++对象使得C++应用程序 使用ECPG功能可能好于在C++代码中直接写一些嵌入SQL命令。 已经创建三种文件:一个C文件(`*.pgc`), 头文件和C++文件: `test_mod.pgc` 执行SQL命令的子程序模块嵌入C中。它将通过预处理器被转换为 `test_mod.c`。 ``` #include "test_mod.h" #include &lt;stdio.h&gt; void db_connect() { EXEC SQL CONNECT TO testdb1; } void db_test() { EXEC SQL BEGIN DECLARE SECTION; char dbname[1024]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT current_database() INTO :dbname; printf("current_database = %s\n", dbname); } void db_disconnect() { EXEC SQL DISCONNECT ALL; } ``` `test_mod.h` C模块中(`test_mod.pgc`)使用函数声明的头文件通过 `test_cpp.cpp`被包含。 这个文件在声明周围有一个`extern "C"`块,因为 它将从C++模块链接。 ``` #ifdef __cplusplus extern "C" { #endif void db_connect(); void db_test(); void db_disconnect(); #ifdef __cplusplus } #endif ``` `test_cpp.cpp` 该应用程序主要代码,包含`main`程序和例子中C++类。 ``` #include "test_mod.h" class TestCpp { public: TestCpp(); void test(); ~TestCpp(); }; TestCpp::TestCpp() { db_connect(); } void TestCpp::test() { db_test(); } TestCpp::~TestCpp() { db_disconnect(); } int main(void) { TestCpp *t = new TestCpp(); t-&gt;test(); return 0; } ``` 为了编译应用程序,如下进行。 通过运行`ecpg`, 转换`test_mod.pgc`到`test_mod.c`, 使用C编译器通过编译`test_mod.c`产生`test_mod.o`。 ``` ecpg -o test_mod.c test_mod.pgc cc -c test_mod.c -o test_mod.o ``` 下一步,使用C++编译器通过编译`test_cpp.cpp`、 生成`test_cpp.o`。 ``` c++ -c test_cpp.cpp -o test_cpp.o ``` 最后,链接这些对象文件,`test_cpp.o` 和`test_mod.o`到一个可执行文件中,使用C++编译器驱动: ``` c++ test_cpp.o test_mod.o -lecpg -o test_cpp ```