【问题标题】:Is it safe to use enum params and return values in SDK API?在 SDK API 中使用枚举参数和返回值是否安全?
【发布时间】:2011-11-01 08:08:49
【问题描述】:

我想创建一个 SDK,它包含一个带有公共 API 的头文件 sdk.h 和一个带有实现的已编译 DLL。

If the code looks like:
//////////
// sdk.h
//////////

enum eAction
{
    Action1,
    Action2,
    Action3
};


class Item
{
protected:
    virtual ~Item(){}
public:
    virtual void Do(eAction action) = 0;
    virtual  void Release()  = 0;
};

extern "C"
{
    Item * CreateItem();
}


//////////
// sdk.cpp
//////////

class ItemImpl: public Item
{
public:

    virtual void Do(eAction action)
    {
        printf("%d", (int)action);
        // do something
    }

    virtual  void Release()
    {
        delete this;
    }
};


Item * CreateItem()
{
    return new ItemImpl;
}


//////////
// main.cpp client side
//////////

int main(int argc, char* argv[])
{
    Item *pItem = CreateItem();

    pItem->Do(Action1);

    pItem->Release();

    return 0;
}

// The file sdk.h is the public API.
// The file sdk.cpp is the implementation and it is compiled to sdk.dll.
// The file main.cpp is the client code that uses the SDK.

我的问题是:

如果 SDK 和客户端代码是使用不同的编译器编译的,那么在公共 API(方法 Do(action))中使用枚举参数和返回值是否安全?例如 SDK 是用 VC 编译的,客户端代码是用 gcc 编译的。不同的编译器是否可以使用不同的大小(2,4 或 8 字节)来表示枚举?

【问题讨论】:

  • 标准允许不同的大小,重要的问题(我不知道答案,因此这是一个评论)是平台上的 C++ ABI(s)是否你关心的,指定如何决定枚举的底层类型。如果您不知道您关心什么平台,那么您必须将其视为不属于 ABI 的一部分,因此您不能将 enum 传递到可执行边界,就像传递 std::string 一样。
  • 我认为这是现实冲突的一个例子:osdir.com/ml/android-ndk/2010-10/msg00559.html。假设帖子属实,Android 的工具链默认配置为在可能的情况下使用short 枚举,但一些libstdc++ dll 至少使用int。因此,适合short 的枚举在两者之间是不兼容的,除非您使用-fno-short-enums 进行编译。因此,如果您的“两个编译器”都是 GCC,但一个有一个没有-fshort-enums,那么您的建议可能是不安全的。如果小于int 的参数作为int 传递,你可能会侥幸成功。

标签: c++ api visual-c++ gcc sdk


【解决方案1】:

根据我的理解,允许编译器选择代表枚举的最终大小,但是您也可以通过定义一个未使用的值来强制大小为最小值,例如 ActionForceDword = 0xFFFFFFFF

或者,您可以将参数声明为整数类型。但是,您仍然受制于就给定类型的大小达成一致的编译器。

【讨论】:

    【解决方案2】:

    不同的编译器可能会为您的enum 提供不同的大小,但对于一个好的设计来说,这无关紧要。我的意思是...您不会因为 int 在不同平台上的大小不同而停止使用它,对吗?

    编辑:

    如果您坚持要求您的类型具有相同的大小,请使用 int32 而不是 enum。没有办法(至少是可移植的方式)保证enum 在所有平台上都具有相同的大小。

    【讨论】:

    • 我不在公共 API 中使用 int。我使用像 int32_t 这样的类型。我不知道你所说的“好的设计”是什么意思,但主要目标是代码在与不同的编译器一起使用时可以工作。
    • 在一个好的设计中,你可以使用 returnValue == Action1 之类的东西,所以存储空间应该无关紧要。你为什么担心这个?
    • 存储很重要,因为枚举是方法的参数。一个编译器生成将输入参数推入堆栈的代码,另一个编译器生成将参数从堆栈中弹出的代码。如果第一个编译器将枚举视为 2 个字节,而第二个编译器将枚举视为 4 个字节,那么我预计代码将无法正常工作(崩溃)。
    猜你喜欢
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    相关资源
    最近更新 更多