ECPG 對 C++ 應用程式提供了一些有限的支援。本節描述了一些注意事項。
ecpg 預處理器接受一個用 C(或類似 C 的語言)編寫並嵌入 SQL 命令的輸入檔案,將嵌入的 SQL 命令轉換為 C 語言塊,最後生成一個 .c 檔案。當在 C++ 下使用時,ecpg 生成的 C 語言塊所使用的庫函式的標頭檔案宣告被包裝在 extern "C" { ... } 塊中,因此它們應該能與 C++ 無縫協作。
然而,總的來說,ecpg 預處理器只理解 C;它不處理 C++ 語言的特殊語法和保留字。因此,在 C++ 應用程式程式碼中使用 C++ 特有複雜功能的某些嵌入式 SQL 程式碼可能會導致預處理不正確或無法按預期工作。
在 C++ 應用程式中使用嵌入式 SQL 程式碼的一種安全方法是將 ECPG 呼叫隱藏在一個 C 模組中,C++ 應用程式程式碼透過呼叫該模組來訪問資料庫,然後將該模組與其餘的 C++ 程式碼連結起來。關於這一點,請參閱 第 34.13.2 節。
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; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; } void Test::test() { EXEC SQL SELECT current_database() INTO :dbname; printf("current_database = %s\n", dbname); } TestCpp::~TestCpp() { EXEC SQL DISCONNECT ALL; }
此程式碼將產生類似以下的錯誤
ecpg test_cpp.pgc
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); }
如果您理解 ecpg 預處理器在 C++ 中的這些技術限制,您可能會得出結論,在連結階段連結 C 物件和 C++ 物件以使 C++ 應用程式能夠使用 ECPG 功能,可能比直接在 C++ 程式碼中編寫一些嵌入式 SQL 命令要好。本節透過一個簡單的示例描述了一種將某些嵌入式 SQL 命令與 C++ 應用程式程式碼分離的方法。在此示例中,應用程式是用 C++ 實現的,而 C 和 ECPG 用於連線到 PostgreSQL 伺服器。
需要建立三種檔案:一個 C 檔案(*.pgc)、一個頭檔案和一個 C++ 檔案
test_mod.pgc
#一個用於執行嵌入 C 中的 SQL 命令的子例程模組。它將被預處理器轉換為 test_mod.c。
#include "test_mod.h" #include <stdio.h> void db_connect() { EXEC SQL CONNECT TO testdb1; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; } 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->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
最後,使用 C++ 編譯器驅動程式將這些物件檔案 test_cpp.o 和 test_mod.o 連結成一個可執行檔案
c++ test_cpp.o test_mod.o -lecpg -o test_cpp
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表格 報告文件問題。