【问题标题】:Conditional C/C++ struct definitions条件 C/C++ 结构定义
【发布时间】:2016-12-04 17:19:30
【问题描述】:

我偶然发现了一些看起来像这样的代码:

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 部分中除了默认构造函数之外没有任何内容,如上所示。

【问题讨论】:

  • 虚函数肯定会破坏代码。它们需要结构内部的额外存储空间(所谓的 vtable 指针)。
  • struct 的开头添加char* empty; 可能会帮助您添加虚函数,尽管这是一个非常可怕的解决方案

标签: c++ c gcc struct one-definition-rule


【解决方案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 的便捷方式

【讨论】:

  • 我没有意识到它们会是不同的结构(C++ 的名称修饰)。然后,当代码来回传递它们时,代码会将它们转换为另一个。在 C++ 文件中可能有调用“new”的 C 函数,但没有。我看到 C 代码:“SomeStruct * ss = calloc(1, sizeof(SomeStruct));”。我认为这是已经完成的问题。他们要么使用 new/delete,要么使用 malloc/free。他们不能混合它们,所以他们总是要么创建/破坏一个结构,要么另一个。所以构造函数对于某些(大多数)结构是未使用的。
  • @PeterS6g 我会等待有关结构名称修改的一些确认。对我来说,这似乎是无稽之谈。我几乎可以肯定结构的名称没有被破坏。仅仅是因为结构的定义没有保存到目标文件中(即使它们会保存,也添加了修改以使重载函数的内部名称不同;这对结构没有意义)。
  • 我实际上是在 gdb 中查找符号,但我看不到任何损坏的证据(但我不确定 gdb 是否通过自动对它们进行解码来隐藏这些)。跨度>
  • @HolyBlackCat @PeterS6g 我的意思实际上是结构的成员函数和将结构作为参数的函数被破坏了。结构本身甚至不会出现在符号表中。例如,假设 C 源文件中有一个函数 void f(SomeStruct),而 C++ 源文件中有一个函数 void f(SomeStruct),它们会以不同的符号出现
猜你喜欢
  • 2015-06-03
  • 1970-01-01
  • 2012-01-12
  • 2015-05-23
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多