我最近在纯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 ++是否处理了与C不同的typedef?以某种方式混淆,......
答案 0 :(得分:5)
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
本身!),你不能只提供其他类型(你正在尝试的那个)使用typedef
创建相同的名称。
无论如何,你正在做的事情相当奇怪,让CSV_T
意味着struct CSV_T*
。我建议不要这样做。
如果您只是坚持使用typedef struct CSV_T CSV_T
,那么这将适用于两种语言,但尝试使用相同名称创建不同的类型是不可行的。< / p>
答案 1 :(得分:4)
C ++标准的附录C说:
7.1.3
更改: C ++ typedef名称必须与同一作用域中声明的任何类类型名称不同(除非typedef是具有相同名称的类名的同义词)。在C中,在同一范围内声明的typedef名称和结构标记名称可以具有相同的名称(因为它们具有不同的名称空间)。
示例:
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
对原始功能的影响:删除语义定义明确的功能。
难以转换:语义转换。必须重命名两种类型中的一种。
使用范围广泛:很少。