变量在内存中的存储

4

如果我有一个像这样的全局变量列表...

int a;
char b;
float c[10];
double d[3];

我在一个类中列出了一系列相同的变量...

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
}

所有变量在内存中的排列顺序是相同的吗?也就是说,在全局列表和类列表中,'b'是否保证紧随'a'存储?

编辑:我问这个问题是因为我想A)一次性将数据从一个复制到另一个,并B)想作为工作批次检查它们之间的任何差异。如果主要问题的答案是否定的,那么有没有人能提出解决方法,最好尽可能不改变现有的代码。

8个回答

8
不。我认为C++标准对全局变量的内存布局没有任何保证。

2
它确实保证了某些东西。具有相同访问说明符的连续声明的类/结构元素的顺序被保留。但可能涉及一些填充。 - sellibitze
2
是的,但 Jesper 说的是“全局变量”。 - Skilldrick

6
为什么不使用类型为test_type的全局对象来替代定义多个全局变量呢?
class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
};

test_type global;

现在,使用“global”的副本初始化一个新的test_type对象非常简单。

1

C/C++标准并不要求变量按照声明顺序存储。因此,编译器可以自由地按照它们想要的顺序存储变量。但是保证它们将按照声明顺序初始化。这对全局变量和类成员变量都适用。

关于全局变量的一些注意事项:在编译单元中,它们将按照指定顺序进行初始化,但这种保证不适用于跨编译单元。


0

不,这并不是保证的。根据您想要做什么,您可以使用指向成员运算符来确保您知道成员变量的相对地址。

因此,在您的类中:

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
}

void* pa = &test_type::a;
void* pb = &test_type::b;
void* pc = &test_type::c;
void* pd = &test_type::d;

void main()
{
  std::cout << "Relative address of member 'a' " << (int)pa <<  std::endl;
  std::cout << "Relative address of member 'b' " << (int)pb <<  std::endl;
  std::cout << "Relative address of member 'c' " << (int)pc <<  std::endl;
  std::cout << "Relative address of member 'd' " << (int)pd <<  std::endl;
}

据我所知,它也可以与 MSVC 和 GCC 一起使用。

2
这是因为类/结构体中定义的变量顺序是有保证的,只有全局变量没有保证。 - kdgregory
也许你是对的,但我的解决方案并不意味着任何额外的操作,一般来说它不依赖于一个原则,这个原则可以很容易地通过实现进行改变。(我不完全确定这会如何影响对齐问题...) - progician
你的“解决方案”证明了一个已知的事实。它并没有解决原帖中所期望的将全局变量一次性复制到结构体的目标。 - kdgregory
一个结构体的布局(除了对齐)不依赖于具体实现。我没有 ANSI C 或 C++ 规范的副本,但这是 K&R 所说的(第二版,第 213 页):“结构体成员的地址按照它们声明的顺序递增。” - kdgregory

0

我认为人们忽略了重点。假设任何布局都是危险的,因为这可能会因CPU、编译器甚至优化程度而改变。

C++将生成默认的复制赋值函数,就好像您编写了以下内容:

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
public:
    test_type &operator=(const test_type &other)
    {
     // copy all of the members one by one.
    }
}

唯一的注意事项是默认运算符只复制成员,包括指针。如果您动态分配了与指针相关联的内容,则必须在运算符中显式处理新的内存分配和数据复制。

那么?在这种情况下,隐式生成的赋值运算符并不会造成任何问题。 - sellibitze
当然不是。我认为创建类使默认运算符正常工作是一个好的实践。例如,我使用std::string而不是char *。 - Tim Allman

0

内存分配取决于编译器。因此,无法保证全局和类成员变量的连续分配或相同分配。


0

不,你不能依赖那个。变量的内存分配取决于编译器。


0
Mick - 为了实现你想要的(复制/测试),你只需要:
  • 为test_type类添加一个构造函数以及一个非构造函数init_from_globals()(其代码逐个复制4个值,通过循环或memcopy复制数组)。

  • 添加一个“diff_from_globals()”方法,再次逐个比较4个成员的差异

虽然实现起来不太高效/优雅,但封装在一个方法中,这种不优雅性完全隐藏在其他代码之后 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接