我在最近的一次采访中被问到有关C++结构字段对齐的问题,并且理论上C和C++在结构打包中遵循相同的策略.
Hovewer,这是错误的假设.采访者说,一般来说,C和C++以不同的方式包装结构,我们永远不应该期待相反的结果.恕我直言,这是一个奇怪的声明.pack "C"
在C++中没有用于双语C/C++头文件的结构限定符.
因此在实践中,它可能意味着您无法在C++中创建结构并将其传递给C库,因为通常它的字段将以不同的方式对齐并具有不同的偏移量.但实际上,大多数程序员都非常依赖这种互操作性,直到他们将一个指向C POD结构的指针转换为对这个结构的C++包装器的引用,并使用了一些辅助方法.你能澄清一下这个问题吗?
你能给我一些关于对象标题中存储内容的信息吗?我知道,它可能依赖于JVM,但至少可能对HotSpot有用吗?我正在寻找第一行的具体描述.
我已经阅读了一些我无法用我发现的信息验证的信息.也许你有一个指向OpenJDK维基的链接?
在我的第一个例子中,我使用了两个位域int64_t
.当我编译并获得类的大小时,我得到8.
class Test
{
int64_t first : 40;
int64_t second : 24;
};
int main()
{
std::cout << sizeof(Test); // 8
}
Run Code Online (Sandbox Code Playgroud)
但是,当我将第二个bitfeild更改int32_t
为类的大小时,会增加到16:
class Test
{
int64_t first : 40;
int32_t second : 24;
};
int main()
{
std::cout << sizeof(Test); // 16
}
Run Code Online (Sandbox Code Playgroud)
这种情况发生在GCC 5.3.0和MSVC 2015上.但为什么呢?
我可以将同一类型的连续数据成员视为范围吗?例如:
struct X
{
int a, b, c, d, e;
};
X x = {42, 13, 97, 11, 31};
std::sort(&x.a, &x.a + 5); // kosher?
Run Code Online (Sandbox Code Playgroud) 我在阅读c ++中的虚拟继承时在网站上发现了这个
使用多重继承时,有时需要使用虚拟继承.一个很好的例子是标准的iostream类层次结构:
//Note: this is a simplified description of iostream classes
class ostream: virtual public ios { /*..*/ }
class istream: virtual public ios { /*..*/ }
class iostream : public istream, public ostream { /*..*/ }
//a single ios inherited
Run Code Online (Sandbox Code Playgroud)
C++如何确保只存在虚拟成员的单个实例,而不管从中派生的类的数量是多少?C++使用额外的间接级别来访问虚拟类,通常是通过指针.换句话说,iostream层次结构中的每个对象都有一个指向ios对象的共享实例的指针.额外的间接级别有轻微的性能开销,但这是一个很小的代价.
我对声明感到困惑:
C++使用额外的间接级别来访问虚拟类,通常是通过指针
任何人都能解释一下吗?
c++ inheritance multiple-inheritance virtual-inheritance object-layout
更具体地说,假设A
是一个可访问的基类B
,下面的代码是否会产生未定义的行为,并且断言是否根据标准禁止触发?
void test(B b1, B b2) {
A* a2 = &b2;
auto offset = reinterpret_cast<char*>(a2) - reinterpret_cast<char*>(&b2);
A* a1 = reinterpret_cast<A*>(reinterpret_cast<char*>(&b1) + offset);
assert(a1 == static_cast<A*>(&b1));
}
Run Code Online (Sandbox Code Playgroud)
编辑:我知道所有常见的编译器供应商都以一种与隐式假设兼容的方式实现C++对象布局(即使在考虑虚拟继承时)test
.我正在寻找的是标准中此行为的保证(隐式或显式).或者,也可以接受标准提供的对象存储布局保证范围的相当详细的描述,作为不保证这种行为的证据.
介绍:
我使用JOL(Java对象布局)工具来分析Java对象的内部和外部碎片以用于研究目的.
在这样做时,我偶然发现了以下内容:
x@pc:~/Util$ java -jar jol-cli-0.9-full.jar internals sun.reflect.DelegatingClassLoader
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are …
Run Code Online (Sandbox Code Playgroud) 我使用了一个名为JOL(Java Object Layout)的工具,它试图分析对象布局.它带有一个cli
,我用它来分析java.lang.Integer
.我看到Integer对象占用了12个额外的字节用于开销.该开销可以是4个字节用于该对象所属的类的地址,另外4个用于垃圾收集,但剩余的4个字节呢?我知道对象有一个整数hashCode值,但我不认为它是唯一的(即它不使用内存的位置,它使用原始值代替)因为:
Integer a = new Integer(12);
Integer b = new Integer(12);
System.out.println(a.hashCode() == 12 && b.hashCode() == 12);
// prints: true
Run Code Online (Sandbox Code Playgroud)
日志:
$ java -jar jol-cli/target/jol-cli.jar internals java.lang.Integer
# WARNING: Unable to get Instrumentation. Dynamic Attach failed. You may add this JAR as -javaagent manually, or supply -Djdk.attach.allowAttachSelf
# Running 64-bit HotSpot VM.
# Using compressed oop with 0-bit shift.
# Using compressed klass with 0-bit shift.
# Objects are 8 bytes …
Run Code Online (Sandbox Code Playgroud) 这是一个很大的问题,因此我要求参考而不是小册子大小的答案。我正在进行Stroustrup的C ++之旅,看来对象的布局方式是内存是许多C ++功能设计的基础,例如POD,聚合,带有虚拟成员的类。
不幸的是,Tour本身并没有详细介绍此主题,而对一些标准参考文献(例如C ++ Primer 5ed和TCPPPL 4ed)的ToC进行浏览并不能显示它们是否涉及该主题。
在什么条件下可以安全地std::memcpy
从一个对象复制到另一个对象?
例如,什么样的条件必须T
,src
并dest
满足是安全的以下内容:
template <typename T>
void copy_bytewise(T& dest, const T& src) {
std::memcpy(&dest, &src, sizeof(T));
}
Run Code Online (Sandbox Code Playgroud)
我们可以假设的唯一的事情src
和dest
是他们不重叠1。特别是,src
或者dest
可以是对成员或基类的引用。
我对参考标准的答案很感兴趣,但是如果这与通常的做法不同(例如,Itanium 的事实上的 C++ ABI),我也想知道。
请注意,如本示例所示,T
满足TriviallyCopyable (TC) 概念是不够的。是 TC 但不是 memcpy 安全的(由于对派生类的成员重复使用填充)。base
我特别感兴趣的是,如果有任何T
单独的条件是充分的(不一定是必要的),而不需要条件src
和dest
(通常不能静态确定)。
1具体来说,我的假设是,如果它们确实重叠,它们在T
与 for相同的条件下仍然可以安全地复制std::memcpy
,但使用std::memmove
代替。如果假设不正确,它可能是答案的一部分。
object-layout ×10
c++ ×7
java ×3
jol ×3
jvm ×3
bit-fields ×1
c ×1
c++11 ×1
inheritance ×1
integer ×1
iterator ×1
memcpy ×1
pointers ×1
stl ×1
struct ×1