【问题标题】:Porting #define from C++ to C#将#define 从 C++ 移植到 C#
【发布时间】:2018-03-07 14:15:53
【问题描述】:

我有一个旧的 MCPP 项目,它被用作在机器上运行的 C++ 代码和在台式计算机上运行的 C# 之间的通信层。最近我们决定尝试杀死这个“胶水”项目。

该项目中有一些用于通信的常量列表,它们最好用作 C++ 和 C# 中的外部链接。

一位同事在使用以下技巧将常量的更改保存在一个地方之前曾做过类似的事情:

#if !__cplusplus
    public const string
#else
    static const TCHAR* const
#endif
                                XML_V1_TagRoot = "r";

__cplusplus 是根据编译器设置的,所以前置处理器让每个编译器看到它可以编译什么。

现在我遇到了一堆#define 类型的语句的问题:

#define TX_TAG2xHWID_PARAMETER  _T("PR")

_T() 是一个宏。所以我尝试了以下方法:

#if __cplusplus
    #define     TX_TAG2xHWID_PARAMETER _T("PR")
#else
    internal const string   TX_TAG2xHWID_PARAMETER = "PR";
#endif

这不起作用,因为 C# 对定义没有价值。 source

然后我尝试了:

#if __cplusplus
    #define                 TX_TAG2xHWID_PARAMETER \
#else
    internal const string   TX_TAG2xHWID_PARAMETER =
#endif

#if __cplusplus
                                                _T(\
#endif
                                                    "PR"
#if __cplusplus
                                                        )
#else
                                                        ;
#endif

这里的问题是 C# 不允许多行 #define

基本上问题在于#define 本身就是一条预处理指令,但只有在文件在 C++ 项目中编译时才应执行。

我也尝试过让 C# 项目认为它是注释,将 /**/ 放入不同的 #if,但我没有成功。

那么,有没有人知道如何让 C# 编译器不抱怨它不应该尝试编译的那一行?

【问题讨论】:

  • 为什么你甚至试图将 c++ 和 c# 放在同一个文件中?你是想用另一个胶水项目杀死一个胶水项目吗?
  • 我们偶尔会看到正确标记为 C 和 C++ 的代码';这可能是关于多语言 C++/C# 问题的第一个。
  • 你是什么意思“这不起作用,因为 C# 对定义没有价值。” ?看来 C++ 会有一个#define TX_TAG2xHWID_PARAMETER,而 c# 会有一个internal const string
  • 您真的创建过 Unicode 版本吗?如果没有,只需完全删除 _T() 宏。对于 MS 来说,它们是一个有用的 hack,可以在 MFC 等库中支持这两种类型,但它们不应该出现在用户代码中。
  • C# 没有预处理器,它只支持带有#if 的条件编译。您使用#if 测试的符号只能是项目设置。这不是您必须解决的问题,它只有一种字符串类型和一种语言语法。所以这些#defines 都不相关。

标签: c# c++ variadic-macros


【解决方案1】:

一种可能的解决方案是给 C# 一个名为 _T 的函数(它只返回它的参数),然后坚持原来的方法:

#if !__cplusplus
    public const string
#else
    static const TCHAR* const
#endif
                                TX_TAG2xHWID_PARAMETER = _T("PR");

【讨论】:

  • 他必须将 C# 版本声明为 static readonly
  • 在那条路上,我还建议 C++ 方面使用using string = std::wstring。保持更多的共同代码。
【解决方案2】:

一种完全不同的方法(这就是为什么它是一个单独的答案)是在构建时使用脚本生成 C++ 头文件和 C# 文件。这样,需要编辑的实际来源类似于

output_text XML_V1_TagRoot "r"
output_text TX_TAG2xHWID_PARAMETER "PR"
output_int  FUNKY_INT_PARAM 43

还有乱七八糟的#ifs都是脚本产生的。

【讨论】:

    【解决方案3】:

    您是否考虑过将字符串放入资源中?这两者都可以使用符号名称从 C++ 或 C# 访问,并且字符串将位于一个位置,并且由于字符串转义的差异而没有问题。

    您还可以在构建中引入一个步骤,该步骤采用字符串列表及其符号名称并创建两个输出文件:一个用于 C++,一个用于 C#,顶部有重要注释:

    // This file is machine generated. To add a constant, edit the file xxxxx
    // and rebuild with the command xxxx
    

    这至少会将所有字符串和符号名称放在一个位置,但会稍微复杂化您的构建过程。是的,这与使用字符串资源完全相同,只是您使用的是自制工具/脚本。

    【讨论】:

      【解决方案4】:

      除非你有充分的理由保持 TX_TAG2xHWID_PARAMETER 和类似的参数内联,否则你可以替换你的

      #if __cplusplus
          #define     TX_TAG2xHWID_PARAMETER _T("PR")
      #else
          internal const string   TX_TAG2xHWID_PARAMETER = "PR";
      #endif
      

      #if __cplusplus
          LPCTSTR     TX_TAG2xHWID_PARAMETER = _T("PR");
      #else
          internal const string   TX_TAG2xHWID_PARAMETER = "PR";
      #endif
      

      【讨论】:

        猜你喜欢
        • 2013-05-01
        • 2018-03-30
        • 1970-01-01
        • 1970-01-01
        • 2012-08-15
        • 1970-01-01
        • 2019-07-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多