Условные определения структур 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