【问题标题】:C library - use in C++: redefinition, different type modifiersC 库 - 在 C++ 中的使用:重新定义、不同的类型修饰符
【发布时间】:2016-07-14 10:10:41
【问题描述】:

我最近用纯 C 构建了一个 CSV 库。 头文件如下:

  #ifndef CSV_H
  #define CSV_H

    #include "unicode/ustdio.h"
    #include "unicode/uchar.h"
    #include "unicode/ucsdet.h"
    #include "unicode/ustring.h"

    #define T CSV_T
    typedef struct T *T;

    extern T    CSV_new(char *filename);
    extern void CSV_free(T *csv);
    extern int  CSV_length(T csv);
    extern void CSV_print_info(T csv);
    extern UChar **CSV_get_header(T csv);
    extern UChar ***CSV_get_values(T csv);
    extern long CSV_get_num_columns(T csv);
    extern long CSV_get_num_lines(T csv);
    extern char *CSV_get_charset(T csv);

    #undef T
    #endif

struct CSV_T 的实际定义是在代码文件中完成的,以隐藏实现。我经常在使用纯 C 的不同项目中使用该库,没问题。现在我想在使用 C++ 构建的 GUI 应用程序中重用代码,我收到以下错误消息:

Error   C2373   'CSV_T': redefinition; different type modifiers     ... xxx\Projects\LibCSV\LibCSV\csv.h    10  

C++ 处理的 typedef 是否与 C 不同?莫名其妙地混淆了,...

【问题讨论】:

  • 发布你的minimal reproducible example,而不是这个“...”废话
  • 还有一点批评——你应该使用const char*,你为什么要使用一个宏来代替已经很短的CSV_T来取代单字母T?这真的很糟糕。
  • typedef struct T *T 对于 C++ 代码来说不是一个好主意。
  • 给你。同意const char *。该定义只是为了不同库之间的一致性。不好,好吧,但我已经习惯了,我想它不会伤害编译器,...:-)
  • 在您的错误报告中紧接发布的错误消息的那一行应该非常有启发性,向您展示之前的版本在哪里,以及实际的区别是什么。为什么你没有在你的问题中包含它仍然是一个谜。 “它不会伤害编译器”——显然 C++ 编译器不同意这种观点。

标签: c++ typedef redefinition


【解决方案1】:

Here 是您的 MCVE 的样子:

typedef struct T *T;

这是一个完整的单行源文件,它重现了问题并且没有依赖关系。没有宏,没有标题,没有不必要的代码。

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:1:19: error: conflicting declaration 'typedef struct T* T'
 typedef struct T *T;
                   ^
main.cpp:1:16: note: previous declaration as 'struct T'
 typedef struct T *T;
            ^

它在 C 中起作用的原因是 T 还不是结构的名称;你需要struct 前缀。

在 C++ 中,这不是真的,因为 struct 前缀并不是必需的。一旦你声明 T 是一个类(令人困惑的是,你在 typedef 本身中做了这个!),你不能只给出其他类型(你试图用 @ 创建的那个987654329@) 同名。

无论如何,你所做的事情都相当奇怪,让CSV_T 意味着struct CSV_T*。我建议干脆不要这样做。

如果您只是坚持使用 typedef struct CSV_T CSV_T,那么这在两种语言中都可以使用,但尝试使用相同名称创建一个 不同 类型是行不通的。

【讨论】:

  • 好的,所以有区别。那我再去看看源代码,...非常感谢!
【解决方案2】:

C++ 标准的附录 C 说:

7.1.3

更改: C++ typedef 名称必须不同于在同一范围内声明的任何类类型名称(除非 typedef 是具有相同名称的类名称的同义词)。在 C 中,在同一作用域中声明的 typedef 名称和 struct 标记名称可以具有相同的名称(因为它们具有不同的命名空间)。

例子:

typedef struct name1 { /.../ } name1; // valid C and C++
struct name { /.../ };
typedef int name; // valid C, invalid C++

基本原理:为便于使用,C++ 在用于对象声明或类型转换时,不要求类型名称以关键字 class、struct 或 union 作为前缀。

例子:

 class name { /.../ };
 name i; // i has type class name

对原始特征的影响:删除语义明确的特征。

转换难度:语义转换。必须重命名这两种类型中的一种。

应用的广泛程度:很少。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 2016-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多