【问题标题】:Add External Dependencies to C++ DLL file将外部依赖项添加到 C++ DLL 文件
【发布时间】:2013-05-31 22:21:23
【问题描述】:

我在 MV C++ 2012 中创建了一个 DLL,当我使用

Dumpbin /Exports filename

DLL 文件中的函数名称内部有一个等号。我不得不使用 公共语言运行时支持 (/crl),因为我使用了 C# 中的 DLL。这就是为什么函数的名称会显示等号的原因吗?我的头文件:

#ifdef ColorDLL_EXPORTS
#define ColorDLL_API __declspec(dllexport)
#else
#define ColorDLL_API __declspec(dllexport)
#endif

extern "C"{
ColorDLL_API int ColorSelect(int i);
}

ColorDLL.cpp

#include "stdafx.h"
#include "ColorDLL.h"
#using <ColorDiologeClass.dll>

extern "C"{
ColorDLL_API int ColorSelect(){
ColorDiologeClass::Class1::ColorReturn(1);
return 1;
}

} 当我使用 Dumpbin 时,名称显示如下:

Name
ColorSelect = _ColorSelect

这是为什么?我希望它显示为 ColorSelect,而不是 ColorSelect = _ColorSelect。如果我这样离开它,我将如何从需要确切函数名称的 JMP 之类的程序中调用此函数?会是 ColorSelect 吗?还是 ColorSelect = _ColorSelect?

【问题讨论】:

  • 不要修复它,这是一件好事。当您更改 C++ 代码时,它可以防止 C# 程序死于可怕的死亡。只需使用 [DllImport] 属性中的 EntryPoint 属性即可。再说一次,当您使用 /clr 编译时,根本不需要这样做。只需创建一个公共 ref 类。
  • 为函数创建一个公共类,它会修复装饰?
  • 你说不要修。但是如果是装饰的,我怎么能在MV之外使用这个功能呢?

标签: c# c++ cmd


【解决方案1】:

名称是“mangled”——返回类型和参数被嵌入到函数的名称中。如果您不想这样,您可以在函数名之前使用extern "C"(或在函数块周围)。

【讨论】:

  • 我尝试在标题和 .cpp 中使用 extern "C",它摆脱了装饰。它现在看起来像这样 名称:ColorSelect = _ColorSelect 但我希望它看起来像 名称:ColorSelect 你知道如何摆脱 = _ColorSelect
  • @user1334858 :你不能——它是 C 语言命名约定的一部分(对于这个编译器)。
【解决方案2】:

这就是名称修饰,这是 c++ 的底层特性,允许它支持函数重载(因为它将函数的参数类型合并到它的名称中)。

Here's another question 更详细。

【讨论】:

    【解决方案3】:

    Microsoft 将其称为“装饰”而不是修饰。它们包括一个名为“undname”的命令行工具,该工具将从修饰名称中生成原始名称:

    C:\>undname ?ColorSelect@@YAHXZ
    Microsoft (R) C++ Name Undecorator
    Copyright (C) Microsoft Corporation. All rights reserved.
    
    Undecoration of :- "?ColorSelect@@YAHXZ"
    is :- "int __cdecl ColorSelect(void)"
    

    如果你想在自己的代码中做同样的事情,你也可以这样做,使用UnDecorateSymbolName

    不管怎样,装饰/修饰不仅支持重载,还支持typesafe linking。类型安全链接源于函数重载,尽管它本身并不是真正的函数重载。

    具体来说,类型安全链接处理(例如)如何处理具有重载的 C++ 代码,例如,floatdoublelong doublecomplex 可能还有 complex,但链接到提供double sqrt(double) 的C 库,但不提供其他重载。在这种情况下,我们通常希望在使用正确的参数时使用它,而不是其他情况。

    即使不涉及函数重载,也可能(或可能)出现这种情况。例如,在纯 C 中你可以这样做:

    #include <stdio.h>
    extern int sqrt(int);
    
    // ...
    printf("%d", sqrt(100));
    

    现在,我们告诉编译器我们正在使用sqrt 的版本,它接受(并返回)int。不幸的是,链接器没有意识到这一点,所以它仍然与标准库中的sqrt 链接,该标准库接受并返回double。结果,上面的代码将打印一些完全无用的结果(通常是0,这并不重要)。

    Typesafe 链接可以防止这种情况——即使它不完全是函数重载,我们仍然有两个同名的函数,但在链接时类型不同。通过将参数类型编码到名称中,链接器可以像编译器一样将其分类。

    当我们在不同的库之间发生名称冲突时,C 中也会出现同样的情况(并且经常出现)。使用传统的 C 编译器,理顺这种混乱可能非常困难(充其量)。使用 C++ 编译器,除非两个库不仅使用相同的名称,而且使用相同数量和类型的参数,否则这根本不是问题。

    【讨论】:

    • 所以最终目标是在 JMP 中调用它,它需要确切的函数名称。我可以使用原始函数名称吗?还是作为修饰名存储在 DLL 中?
    • @user1334858:它作为修饰名称存储在 DLL 中。
    猜你喜欢
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 2016-11-22
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    相关资源
    最近更新 更多