当前位置: 首页 > 知识库问答 >
问题:

c 11(工作草案)标准中的布局兼容性是否太弱?

常培
2023-03-14

当然,答案是否定的,因为写这本书的人想了很久,但是我想知道为什么。

考虑到(无模板的)类通常在头文件中声明,然后包含在单独编译的几个文件中,因此请考虑以下两个文件:

#include <cstddef>

struct Foo {
public:
   int pub;
private:
   int priv;
};

size_t getsize1(Foo const &foo) {
  return sizeof(foo);
}
#include <cstddef>

struct Foo {
public:
   int pub;
private:
   int priv;
};

size_t getsize2(Foo const &foo) {
  return sizeof(foo);
}

一般来说,Foo会在头文件中声明并包含在两者中,但效果如上所示。(也就是说,包含标题并不神奇,它只是将标题内容放在那一行。)我们可以编译两者并将它们链接到以下内容:

#include <iostream>
struct Foo {
public:
   int pub;
private:
   int priv;
};

size_t getsize1(Foo const &);
size_t getsize2(Foo const &);

int main() {
    Foo foo;
    std::cout << getsize1(foo) << ", " << getsize2(foo) << ", " << sizeof(foo) << '\n';
}

一种方法是使用g:

g++ -std=c++11 -c -Wall file1.cc 
g++ -std=c++11 -c -Wall file2.cc 
g++ -std=c++11 -c -Wall main.cc 
g++ -std=c++11 -Wall *.o -o main

(在我的架构和环境上),这表明:8,8,8.每个 file1.cc,file2.cc 和 main.cc

但是,c11标准能保证这一点吗?期望与所有3个Foo的布局兼容真的可以吗?Foo包含私有字段和公共字段,因此它不是c 11标准(工作草案)第9条第7款中定义的标准布局结构:

标准布局类是这样的类:

    < li >没有非标准布局类(或这种类型的数组)或引用类型的非静态数据成员, < li >没有虚函数(10.3)和虚基类(10.1), < li >对所有非静态数据成员具有相同的访问控制(第11条), < li >没有非标准布局基类, < li >要么在最大派生类中没有非静态数据成员,最多有一个具有非静态数据成员的基类,要么没有具有非静态数据成员的基类,并且 < li >没有与第一个非静态数据成员相同类型的基类。

由于我们使用的是结构,并且为了彻底,下一个标准说:

标准布局结构是使用类键结构或类键类定义的标准布局类。标准布局联合是使用类键联合定义的标准布局类。

据我所知,该标准仅定义了标准布局中结构之间的布局兼容性(第9.2条,第18段)。

如果两个标准布局结构(第9条)类型具有相同数量的非静态数据成员,则它们是布局兼容的,并且相应的非静态数据库成员(按声明顺序)具有布局兼容的类型(3.9)。

那么,是否保证所有三个Foo都是布局兼容的,更重要的是为什么呢?

为什么在编译期间为Foo创建不同布局的(非确定性)编译器不是c11编译器?

共有1个答案

楚志强
2023-03-14

这三个Foo是布局兼容的,因为它们是相同的类型,struct::Foo

11 - 如果两种类型 T1 和 T2 是同一类型,则 T1 和 T2 是布局兼容的类型。

这些类是相同的类型,因为它们具有相同的(完全限定)名称并具有外部链接:

9-根据每个翻译单元中指定名称的链接(3.5),多个翻译单元中使用的名称可能指代这些翻译单元中的同一实体。

在命名空间范围中声明的类名,如果未在未命名命名空间中声明(递归),则具有外部链接:

2-当一个名称可能表示与另一个作用域中的声明引入的名称相同的[…]类型[…]时,称为具有链接:
-当一个名称具有外部链接时,它所表示的实体可以通过来自其他翻译单元的作用域或来自同一翻译单元的其他作用域的名称来引用。[…]
4-未命名的命名空间或直接或间接在未命名命名空间中声明的命名空间具有内部链接。所有其他命名空间都具有外部链接。如果一个名称具有未在上面给出内部链接的命名空间范围,则它与封闭的命名空间具有相同的链接,如果它是[…]
-一个命名类(第9条),或在typedef声明中定义的未命名类,其中该类具有用于链接目的的typedef名称(7.1.3)[…]

请注意,允许在不同的翻译单元中出现一个类类型的多个定义,只要这些定义包含相同的标记序列:

6 - 程序中可以有多个类类型定义(条款9)[...],前提是每个定义都出现在不同的翻译单元中,并且[...]每个定义[...]应由相同的标记序列组成[...]

因此,如果Foos有不同的名称,它们就不会是同一类型;如果它们出现在匿名名称空间或函数定义中(内联函数除外;请参见[dcl.fct.spec]/4),它们将没有外部链接,因此不会是同一类型。在任何一种情况下,只有当它们是标准布局时,它们才是布局兼容的。

一些示例:

// tu1.cpp
struct Foo { private: int i; public: int j; };

// tu2.cpp
struct Foo { private: int i; public: int j; };

两个Foo是相同的类型。

// tu1.cpp
struct Foo { private: int i; public: int j; };

// tu2.cpp
struct Foo { private: int i; public: int k; };

违反经销后条例;未定义的行为。

// tu1.cpp
struct Foo { private: int i; public: int j; };

// tu2.cpp
struct Bar { private: int i; public: int j; };

名字不同,所以类型不同。布局不兼容。

// tu1.cpp
struct Foo { int i; int j; };

// tu2.cpp
struct Bar { int i; int j; };

不同的名称,不同的类型,但布局兼容(因为标准布局)。

// tu1.cpp
namespace { struct Foo { private: int i; public: int j; }; }

// tu2.cpp
namespace { struct Foo { private: int i; public: int j; }; }

内部链接;不同类型。

// tu1.cpp
static void f() { struct Foo { private: int i; public: int j; }; }

// tu2.cpp
static void f() { struct Foo { private: int i; public: int j; }; }

无联动;不同类型。

// tu1.cpp
inline void f() { struct Foo { private: int i; public: int j; }; }

// tu2.cpp
inline void f() { struct Foo { private: int i; public: int j; }; }

[dcl.fct.spec]/4的相同类型。

 类似资料:
  • 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI模式下运行MySQL 1.8.4. MySQL对标准SQL的扩展 1.8.5. MySQL与标准SQL的差别 1.8.6. MySQL处理约束的方式 在本节中,介绍了MySQL与ANSI/ISO SQL标准的关系。MySQL服务器有很多对SQL标准的扩展之处,这里介绍了它们是什么,以及使用它们的方法。你

  • C11标准6.5.2.3中给出了以下示例 以下不是有效片段(因为union类型在函数f中不可见): 为什么联合类型对函数f可见有关系? 我在翻阅有关的部分时,看不出其中有甚么不容许这样做的地方。

  • 但是,我找不到任何说明枚举类型与其基础类型的布局兼容的内容。对我来说,这似乎是显而易见的,因为“底层类型”的含义有合理的语义,但它实际上是由标准保证的吗?

  • 我一直在为android开发一个应用程序,它利用了android可比性库(android-support-v4)。在SDK 20之前,我能够在清单中使用以下< code>uses-sdk条目编译我的应用程序。 我的所有为结果启动活动的片段都正确地收到了结果。 有一天(在我更新到SDK 20之前),我在修复lint问题,并根据lint标志的请求将< code > Android:targetSdkV

  • 我目前正在使用gradle,似乎可以通过java插件设置sourcecompatibility和targetcompatibility 我想知道除了与旧的JDK向后兼容之外,我们使用sourcecompatibility/targetcompatibility的原因是什么? 如果没有设置sourcecompatibility/targetcompatibility,升级到最新的java会更容易吗?