我偶然发现了一些看起来像这样的代码:
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部分中有任何内容,如上所示。
答案 0 :(得分: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 ++库公开给C API的便捷方式