【问题标题】:Question about c++ naming conventions关于 c++ 命名约定的问题
【发布时间】:2011-08-21 14:06:43
【问题描述】:

我正在尝试为诸如 win32、mac os、linux、iOs 等平台创建一个抽象层。 我希望这是动态链接的。在不支持此功能的平台上,这应该不是问题,因为据我所知,可以编译为动态库的所有内容都可以编译为静态库,并且对代码的影响最小。

现在,进入正题:

我创建了一个名为 IThread 的接口和一个名为 CThread 的类。我使用了一个名为 CreateThread 的函数,该函数用 extern "C" 定义,以便能够导出它并在库外调用它。这里的问题是,例如在 win32 中已经有一个名为 CreateThread 的函数,因此我得到一个链接器错误。我了解错误及其出现的原因,但我不确定避免这种情况的好方法。我不太喜欢使用奇怪的命名,因为 qt 使用 CreateQtThread。
我的另一个想法是创建一个创建 CThread 实例的线程管理器/工厂,但我不确定这是否是个好主意。

你们怎么看这件事?我之所以这么问,是因为我不想急于解决此类重要的组织问题。

非常感谢

【问题讨论】:

  • 您的问题是什么?您了解错误并且不想重命名您的函数,所以您想知道我们对此有何看法?
  • 是的,如果可能的话,我希望有更多经验的人就此发表意见。谢谢。
  • 您希望您的抽象层仅用于 C++ 还是其他语言(例如 C)?您是想从给定的 C++ 编译器中使用它(如果需要更改编译器,则重新编译抽象层)还是 oyu 需要“编译一次适用于每个 C++ 编译器”?

标签: c++ winapi dll naming extern


【解决方案1】:

我使用了一个用 extern "C" 定义的名为 CreateThread 的函数,以便能够导出它并在库外调用它。

这很糟糕。我不能谈论其他平台,但在 Windows 上导出 C++ 函数非常好。它们只是被破坏了,如果有人更改声明,你会得到一些健全性检查。事实上,这是导出 C++的函数的唯一正确方法。如果您将其声明为 extern "C",您将不会获得命名空间、不会重载,并且如果您的函数中出现异常,使用 /EHsc 编译的人将会遇到麻烦。

首选解决方案:不要将它们声明为 extern "C",并将它们放在命名空间中。

唯一的其他解决方案:好吧,猜猜为什么所有这些 C 库都以 their_lib_prefix_function 为函数前缀...

【讨论】:

  • 我使用 extern "C" 是有充分理由的。如果我使用 Visual Studio 2010 编译 DLL,那么我可以在 Visual Studio 2008 中使用该 DLL,而无需重新编译整个东西。实际上,我可以给某人 DLL 和必要的包含文件(接口),并且该人可以在没有实际源文件的情况下使用 dll 编译项目(因为函数的名称没有被破坏)。
  • @Sanctus:我认为你的理解是错误的。 AFAIK 改造计划在过去 10 年没有改变。
  • 我不确定它是否会在不同版本的 Visual Studio 之间发生变化,但在 gcc 等不同的编译器上会有所不同。这里有一个表格显示:en.wikipedia.org/wiki/Name_mangling
  • @ybungalowbill 还有其他编译器,甚至其他语言
  • ybungalobill:实际上,名称 mangling 在 Visual Studio 的编译器版本中是稳定的。
【解决方案2】:

在我看来,您使用 extern "C" 的决定是合理的,因为它允许从其他语言、编译器等进行访问。但是这样做意味着您不能使用命名空间,因此您只需在函数前面加上一些东西来将它们标识为如果你愿意的话,来自你的图书馆,一个穷人的命名空间。

如果您想使用 extern "C",这是您必须做出的妥协。

【讨论】:

    【解决方案3】:

    好吧,我不知道您是否会喜欢这个,因为我知道与我合作的 C 开发人员认为它不美观。但是,它非常简单并且可以防止这样的碰撞。 (this answer 或多或少提到了“their_lib_prefix_function”注释。)

    所以,每当我使用 C 代码时,我基本上都会使用下划线来“命名空间”我的函数。所以,假设你的命名空间是MegaAbstraction,那么像CreateThread 这样的东西就变成了MegaAbstraction_CreateThread。十分简单。并且没有冲突,除非其他人有一个名为 MegaAbstraction 的命名空间,在这种情况下,我建议找到一个其他人不太可能使用的命名空间。 ;)

    【讨论】:

    • 我的+1,我认为那是简单而优雅的。我认为坚持使用相同的函数名没有任何意义,因为: 1. 只要函数名有意义,没关系。 2. 在一个实际的项目中,有成百上千的事情要操心,因为要为使用特定名称的函数命名而烦恼。
    • :) 谢谢,在这两点上完全同意你的看法。而且,你知道可怕的是,我认为与我一起工作的那些不喜欢我的命名约定的人担心......他们必须输入多少额外的字母。 :D 我的意思是,我曾经使用过这些超长的描述性名称,甚至在它流行之前,虽然我已经削减了自己一点,我的意思是......如果你正在查看他们的代码,那么对他们来说应该很明显对您而言,kfifl() 的含义是什么,如果您无法区分它与 kfifs() 和 kfifc() 和 kfifj() 的含义,那么这是您的问题,而不是他们的问题。耸耸肩。
    • 我会留下来,我不想和这样的人一起工作。我相信一个好的来源是简单明了的,足以被下一个从事它的人理解的来源。编写令人讨厌的代码,除了作者之外没有人理解是真正的维护噩梦。哎呀!
    【解决方案4】:

    您的 CreateThread 是否使用 stdcall 调用约定(又名 WINAPI)?如果使用cdecl调用约定,应将函数名导出为_CreateThread,避免与Win32 CreateThread函数的链接冲突。

    extern "C" _declspec(export) int _cdecl CreateThread(...
    

    【讨论】:

      【解决方案5】:

      Qt 中没有“CreateQtThread”函数,甚至没有类似的东西。有一个 QThread 类,它有构造函数。如果需要,您可以将所有内容放在命名空间中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-17
        • 1970-01-01
        • 1970-01-01
        • 2020-03-12
        • 2016-12-25
        • 2017-02-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多