# 36.13.C++应用程序

36.13.1. 主机变量的作用域

36.13.2. 用C++外部模块开发C++应用程序

ECPG对C++应用程序有一些有限的支持。本节介绍了一些注意事项。

这个ecpg预处理器接收用C(或类似C的语言)编写的输入文件和嵌入式SQL命令,将嵌入式SQL命令转换为C语言块,最后生成C文件C语言块使用的库函数的头文件声明ecpg它们被包裹在外部“C”{…}块在C++下使用,所以它们应该在C++中无缝地工作。

然而,总的来说ecpg预处理器只懂C;它不处理C++语言的特殊语法和保留词。因此,一些C++代码中使用的嵌入SQL代码,使用C++特有的复杂特性,可能无法正确地进行预处理或可能无法按预期工作。

在C++应用程序中使用嵌入式SQL代码的一种安全方法是隐藏C模块中的ECG调用,C++应用程序代码调用该调用来访问数据库,并将其与C++代码的其余部分连接起来。看见第36.13.2节关于那件事。

# 36.13.1.主机变量的作用域

这个ecpg预处理器理解C语言中变量的范围。在C语言中,这相当简单,因为变量的范围基于它们的代码块。但是,在C++中,类成员变量引用在不同的代码块中,与所声明的位置相比,因此ecpg预处理器将无法理解类成员变量的范围。

例如,在以下情况下ecpg预处理器找不到变量的任何声明库名测验方法,因此将发生错误。

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

为了避免这个范围问题测验方法可以修改为使用局部变量作为中间存储。但这种方法只是一种糟糕的变通方法,因为它会使代码变得丑陋,降低性能。

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);
}

# 36.13.2.用C++外部模块开发C++应用程序

如果您了解ecpgC++中的预处理器,你可能会得出结论,链接阶段的C对象和C++对象使C++应用程序使用ECPG特征可以比直接在C++代码中编写一些嵌入式SQL命令更好。本节描述了一个用简单的例子从C++应用程序代码中分离一些嵌入式SQL命令的方法。在这个例子中,应用程序是用C++实现的,而C和ECGP则用于连接PostgreSQL服务器。

必须创建三种类型的文件:C文件(*.pgc)头文件和C++文件:

测试模式。pgc

一个子程序模块,用于执行嵌入在C中的SQL命令。它将被转换为测试模式。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;
}

测试模式。H

包含C模块中函数声明的头文件(测试模式。pgc).它包含在测试cpp。cpp.此文件必须具有外部“C”封锁声明,因为它将从C++模块链接。

#ifdef __cplusplus
extern "C" {
#endif

void db_connect();
void db_test();
void db_disconnect();

#ifdef __cplusplus
}
#endif

测试cpp。cpp

应用程序的主代码,包括主要的例程,在这个例子中是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;
}

要构建应用程序,请按以下步骤进行。转换测试模式。pgc进入测试模式。C通过跑步ecpg,并生成测试模式。o通过编译测试模式。C使用C编译器:

ecpg -o test_mod.c test_mod.pgc
cc -c test_mod.c -o test_mod.o

接下来,生成测试cpp。o通过编译测试cpp。cpp用C++编译器:

c++ -c test_cpp.cpp -o test_cpp.o

最后,链接这些对象文件,测试cpp。o测试模式。o将其编译为一个可执行文件,使用C++编译器驱动程序:

c++ test_cpp.o test_mod.o -lecpg -o test_cpp