c++:相同结构体名称但定义不同时会发生什么?

242 阅读2分钟

背景

最近在学习c++编译原理,好奇当两个结构体具有相同的名称,但定义不同时会发生什么?于是写了个测试小例子测试一下。先说结论:不同编译器行为可能不一样,有可能会按照错误的方式对结构体变量的内存布局进行解释,因此不推荐给一个结构体名称多个不同的定义。 下面是测试案例

代码

// a.h
#pragma once
struct A {
	int x;
	char c;
	float y;
};
// a.cpp
#include "a.h"
A a{ 1,'x',2.0 };
// main.cpp
#include <iostream>
//#include "a.h"
struct A {
	float y;
};

extern A a;

int main() {
	std::cout << "a.y" << a.y << "\n";
	return 0;
}

输出乱值

image.jpeg

分析

编译器能够编译和运行这个程序,可能有几个原因,但关键在于未定义行为的处理方式。在 C++ 中,未定义行为(Undefined Behavior, UB)意味着编译器没有义务在这种情况下生成任何特定的行为,因此具体的结果取决于编译器、平台以及编译器实现细节。在你的特定情况下,编译器可能生成了一个可以运行的程序,但这并不意味着程序的行为是正确的或可移植的。

编译和运行通过的原因

  1. 内存布局:在这个简单的例子中,编译器可能分配了足够的内存以容纳两个成员变量(xy),即使 main.cpp 中只定义了一个 x。当访问 a.x 时,可能正好访问了正确的内存位置,导致程序没有崩溃。
  2. 对齐和填充:在大多数现代计算平台上,数据结构的对齐和填充可能导致 struct A 的内存布局在两个文件中相同或相似。这种情况下,访问 a.x 可能不会引起显著的错误。
  3. 优化器行为:编译器的优化器可能对代码进行了某些处理,使得代码在运行时看似正确。例如,优化器可能会内联一些操作或者简化对内存的访问,从而避免直接的内存冲突。

与内存布局有关

image.jpeg 在main.cpp中对外部变量a进行解析时,float A::y会按照a.cpp中A的内存布局,将int A::x,解释为float A::y