2016-12-04 9 views
2

Я наткнулся на некоторый код, который выглядит следующим образом:Условная C/C++ STRUCT определения

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

Виртуальные функции, безусловно, сломают код. Они требуют дополнительного хранения внутри структуры (так называемый * vtable pointer *). – HolyBlackCat

+0

Добавление символа 'char * empty;' в начале 'struct' может помочь вам добавить виртуальную функцию, хотя это довольно ужасное решение. –

ответ

0

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

Заголовок файла

$ 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++ для C API.

+0

Я не понял, что они будут разными структурами (C++ с именем mangling). Затем код затем бросает один, как другой, когда они передают их назад и вперед. Могут существовать функции C, которые вызывают «новый» в файле C++, но их нет. Я вижу код C, который делает: «SomeStruct * ss = calloc (1, sizeof (SomeStruct));». Я думаю, что это проблема с тем, что было сделано. Либо они используют new/delete, либо malloc/free. Они не могут их смешивать, поэтому они всегда создают или разрушают одну структуру или другую. Поэтому конструктор не используется для некоторых (большинства) структур. – PeterS6g

+0

@ PeterS6g Я бы подождал некоторого подтверждения о том, как сгенерировано имя структуры. Для меня это выглядит как вздор. Я почти уверен, что имена структур не искажены. Просто потому, что определения структур не сохраняются в объектных файлах (даже если бы они были задействованы, было добавлено mangling, чтобы внутренние имена перегруженных функций различались, это не имеет смысла для структур). – HolyBlackCat

+0

Я действительно искал символы в gdb, и я не видел никаких признаков манипулирования (но я не уверен, что gdb скрывает это от меня, автоматически разворачивая их). – PeterS6g