【问题标题】:C vs C++ compilation incompatibility - does not name a typeC 与 C++ 编译不兼容 - 未命名类型
【发布时间】:2018-12-06 06:04:23
【问题描述】:

我正在尝试将供应商的库与我的 C++ 应用程序结合使用。该库主要基于 C,这通常不是 extern "C" 选项的问题,但我遇到了 C++ 编译器不接受的问题。

我将代码简化为以下示例文件。 header.h 代表来自 suppier 库的头文件,main.c/cpp 是我自己的文件。我真正的应用程序是一个 C++ 应用程序,所以我想让它与 main.cpp 一起工作。

header.h(注意u64 u64;这一行):

#ifndef HEADER_H
#define HEADER_H

#include <stdint.h>

typedef uint64_t u64;

union teststruct {
    u64 u64;
    struct {
        u64 x:32;
        u64 y:32;
    } s;
};

#endif

main.c:

#include <stdio.h>
#include "header.h"

int main() {
    union teststruct a;
    a.u64=5;
    printf("%x\n", a.u64);

    return 0;
}

main.cpp(与 main.c 相同,但多了一个 extern "C" 语句):

#include <stdio.h>

extern "C" {
#include "header.h"
}

int main() {
    union teststruct a;
    a.u64=5;
    printf("%x\n", a.u64);

    return 0;
}

使用该行编译 main.c

gcc -o test main.c

编译没有问题。但是,使用 g++ 编译器和命令

编译 C++ 版本
g++ -o test main.cpp

给出以下编译器错误:

In file included from main.cpp:12:0:
header.h:11:9: error: ‘u64’ does not name a type
         u64 x:32;
         ^
header.h:12:9: error: ‘u64’ does not name a type
         u64 y:32;
         ^

问题是供应商对类型和变量名使用了相同的名称 (u64),这似乎是一个坏主意,但 gcc 显然接受了它。我不想更改库(即 header.h),因为它非常大,这在代码中经常发生,我偶尔会得到它的更新。有没有办法让 g++ 接受这种组合,或者修改 main.cpp 以使其编译而不更改 header.h?

【问题讨论】:

  • C 和 C++ 是两种截然不同的语言,具有非常不同的规则和语义。有很多东西是有效的 C 但无效的 C++。如果您的头文件包含有效的 C 但无效的 C++,并且您无法真正编辑头文件以“修复”它,那么您自己也无能为力。而extern "C" 并不是真正的“C 向后兼容模式”,它的主要用途是禁止名称修改,仅此而已。
  • 向您的图书馆供应商提交错误报告。
  • 该库是否声称可用于 C++ 代码?还是只声称是C代码?
  • @Someprogrammerdude 答案和评论是两个非常不同的概念,有着非常不同的规则。有很多东西是有效的 cmets,但问题的答案不是其中之一。

标签: c++ c gcc g++


【解决方案1】:

如果你提到的 C 和 C++ 之间的不兼容是唯一的,你应该能够以编程方式将 header.h 转换为 C++ 兼容的头文件,将其命名为 header.hpp。然后你可以用同样的方法转换新版本。

编译器错误会告诉您应该更改的内容和位置:

header.h:11:9: error: ‘u64’ does not name a type
  1. 打开header.h;
  2. 寻找位置 11:9;
  3. 在此处插入::
  4. 重复所有does not name a type 错误。

一些字符串处理就完成了。

PS:C 到 C++ 转换器也可以做到这一点。

【讨论】:

    【解决方案2】:

    您的头文件似乎在 C++ 中是非法的,因此您不能在编译为 C++ 的代码中 #include 它。如果您无法更改库头文件(例如,通过向库供应商投诉),那么最直接的选择是围绕库编写一个与 C++ 兼容的精简包装器:

    要将您的 C++ 代码与 C 标头隔离开来,请创建 Wrapper.hWrapper.c,其中 .h 对包含在 C++ 中有效,是否包含 header.h,以及提供库交互所需的所有类型和功能。然后,在.c 中,您可以#include "header.h" 并实现所有调用(以及在类型之间安全转换所需的任何操作)。这显然必须编译为 C,而不是 C++。

    【讨论】:

    • 这种方法的缺点是,除非您进行链接时优化,否则它会为每个库调用增加一层额外的过程调用开销。
    【解决方案3】:

    teststruct 在 C++ 中定义了一个作用域。您可以形成合格的 id teststruct::u64。因此名称查找的语言规则说明了这一点,允许类和联合的成员在外部范围内隐藏标识符。一旦引入u64 u64;,不合格的u64就不能引用全局的::u64,只能引用成员。而且成员不是类型。

    在 C union teststruct 中没有定义范围。该字段只能在成员访问中使用,因此永远不会出现冲突。因此,该字段不需要隐藏文件范围类型标识符。

    据我所知,您可以做任何事情来轻松解决它。这个库(这是一个完全有效的 C 库)不是一个有效的 C++ 库。与使用newtry 作为变量名没有什么不同。它需要适应。

    【讨论】:

    • 等等,C没有范围解析操作符?哇,但事后看来是有道理的:)
    • @Rakete1111 - 你是少数只学过 C++ 而不会学过 C 的人之一吗?
    • 没错。我一直认为我知道 C(因为 C++),但我总是被证明是错误的 :)
    • @Rakete1111:请注意,与 C++ 相比,C 编程需要非常 不同的方法(我什至会说完全不同的思维方式)。在某种程度上,我很容易承认我在 C++ 方面非常出色,但在 C 方面非常糟糕,即使我可以同时编写两者。这在你第一次学习时并不明显,所以这就是我提到这一点的原因——如果你假设这些语言中的两段代码应该彼此相似,那么之后的某个时候你只会把头撞到墙上(也许早点,也许晚点)。我忘记了你曾经了解 C 并从头开始的想法。
    • @Mehrdad 反过来也一样。我的 C 是最好的,但我从来没有完全理解 C++。如果需要,我可以使用 C++,但它并不自然,我真的不喜欢它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-27
    相关资源
    最近更新 更多