Условные определения структур C/C++

Я наткнулся на некоторый код, который выглядит так:

typedef struct SomeStruct
{
    int foo;
    void * bar;
#if defined(__cplusplus)
    SomeStruct();
#endif
} SomeStruct;

Он находится в заголовочном файле, который будет включен в файлы.c и.cpp. Это, по крайней мере, технически является нарушением правила единого определения. Очевидное влияние, которое я вижу, состоит в том, что если один из них когда-либо будет объявлен в файле.c, конструктор не будет работать. И, к сожалению, кто-то, кажется, использовал это как образец для правильного способа объявления структур, и объявил пару десятков структур точно так же, как это.

Я пытаюсь понять, насколько это серьезная проблема. Помимо конструктора, возможно, не работает, есть ли другие вероятные последствия? Конструктор реализован в файле.cpp. Я вижу указатели на структуры, выделенные в файле.c (с malloc), которые передаются функциям в файлах.cpp. Насколько я могу судить, они работают правильно (скомпилировано с gcc/g++ 4.6.2 для Suse Linux, если это имеет значение). Что-то сломалось бы, если бы виртуальные функции-члены также были добавлены? На данный момент ни один из этих классов не имеет ничего в своем разделе cplusplus, кроме конструктора по умолчанию, как показано выше.

1 ответ

Это не совсем нарушение ODR. Неформально компилятор C видит тип POD, а компилятор C++ видит класс в глобальном пространстве имен, который станет сущностью с искаженным именем. Что еще более важно, структура объявляется по-разному только для компиляторов C и C++, но она определяется только один раз в исходном файле C++. Скорее всего, в исходном файле C++ есть некоторые функции выделения и освобождения, которые предоставляют конструктор / деструктор C API. Например,

Заголовочный файл

$ cat some_struct.h 
#ifndef SOME_STRUCT_H
#define SOME_STRUCT_H

typedef struct SomeStruct {
    int foo;
    void *var;
#if defined(__cplusplus)
    SomeStruct();
#endif
} SomeStruct;

#if defined(__cplusplus)
extern "C" {
#endif

SomeStruct *some_struct_malloc();
void some_struct_free(SomeStruct **);

#if defined(__cplusplus)
} // extern "C"
#endif

#endif // SOME_STRUCT_H

C++ исходный файл

$ cat some_struct.cpp 
#include "some_struct.h"
#include <cstddef>

SomeStruct::SomeStruct()
{
    foo = 10;
    var = NULL;
}

SomeStruct *some_struct_malloc() { return new SomeStruct; }

void some_struct_free(SomeStruct **pp)
{
    if (*pp)
        delete *pp;
    *pp = NULL;
}

C исходный файл:

$ cat main.c 
#include "some_struct.h"
#include <stdio.h>

int main()
{
    SomeStruct *p = some_struct_malloc();
    printf("%d\n", p->foo);
}

Я бы сказал, что это плохой стиль. Но это работает как удобный способ представить библиотеку C++ API C

Другие вопросы по тегам