Search code examples
c++typedefredefinition

C library - use in C++: redefinition, different type modifiers


I recently built a CSV library in pure C. The header file looks as follows:

  #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

The actual definition of the struct CSV_T is done in the code file, to hide the implementation. I used the library quite often in different projects using pure C, no problem. Now I wanted to re-use the code in a GUI application that is built with C++, and I get the following error message:

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

Does C++ handle something about typedefs different than C? Confusing somehow,...


Solution

  • Here's what your MCVE should look like:

    typedef struct T *T;
    

    This is a complete, one-line source file that reproduces the issue and has no dependencies. No macros, no headers, no unnecessary code.

    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;
                ^
    

    The reason it works in C is that T was not already the name of a struct; you needed the struct prefix.

    In C++, this is not true, because the struct prefix wasn't required in the first place. As soon as you have declared that T is a class (which, confusingly, you did in the typedef itself!), you can't just give some other type (the one you're trying to create with the typedef) the same name.

    It's rather bizarre what you're doing anyway, making CSV_T mean struct CSV_T*. I suggest simply not doing this.

    If you were simply sticking with a typedef struct CSV_T CSV_T then this would work in both languages, but trying to make a different type with the same name just isn't going to work.