c++一道假设性的面试题,求大神

时间:2021-12-05 19:05:40
struct A
{
    int a;
    int b;
    char c;
    char d;
}a;

struct B
{
    int a;
    int b;
    char c;
    char d;
    char e;
}b;
初始化a、b;

a.a=1;  a.b=2; a.c=3; a.d=4;
b.a=1;  b.b=2; b.c=3; b.d=4; b.e=5;

假设a结构体直接复制个b成立:  b = a;

问最后b.e的值是多少?

14 个解决方案

#1


他想知道什么呢,要成立,无非添加隐式转换,或者重载=操作符啥的,想让他=多少就=多少啊。要么就是想考你内存对齐了,这两个结构体占用内存一样的。关键还要看怎么假设他成立的吧,请楼下高人解答 c++一道假设性的面试题,求大神

#2


b.e未知。

在32位系统中对齐到4字节边界的逻辑下,A中四个域都不需要对齐调整,但需要在d后面填充两个字节,以合吃族在A数组类型中,下一个元素依然从4字节边界开始,以保证两个int类型成员正好占据一个32位字。B也一样,需要在e后面填充一个字节。

这样,如果以memcpy的方式把A对象赋值给B对象,e对应的位置正好是A对象中的填充字节,填充字节会是什么数据,这一点很难确定。

#3


引用 1 楼 sublimepan 的回复:
他想知道什么呢,要成立,无非添加隐式转换,或者重载=操作符啥的,想让他=多少就=多少啊。要么就是想考你内存对齐了,这两个结构体占用内存一样的。关键还要看怎么假设他成立的吧,请楼下高人解答 c++一道假设性的面试题,求大神


安在内存对齐补0的话,答案应该是0,但是那人批了我一顿。所以纠结了。

#4


引用 2 楼 u010936098 的回复:
b.e未知。

在32位系统中对齐到4字节边界的逻辑下,A中四个域都不需要对齐调整,但需要在d后面填充两个字节,以合吃族在A数组类型中,下一个元素依然从4字节边界开始,以保证两个int类型成员正好占据一个32位字。B也一样,需要在e后面填充一个字节。

这样,如果以memcpy的方式把A对象赋值给B对象,e对应的位置正好是A对象中的填充字节,填充字节会是什么数据,这一点很难确定。


一开始我也是这么想的但是那面试官说有一个确切的值得,所以就又迷茫。
还是我真的不懂啊

#5


引用 2 楼 u010936098 的回复:
b.e未知。

在32位系统中对齐到4字节边界的逻辑下,A中四个域都不需要对齐调整,但需要在d后面填充两个字节,以合吃族在A数组类型中,下一个元素依然从4字节边界开始,以保证两个int类型成员正好占据一个32位字。B也一样,需要在e后面填充一个字节。

这样,如果以memcpy的方式把A对象赋值给B对象,e对应的位置正好是A对象中的填充字节,填充字节会是什么数据,这一点很难确定。


我是不是被面试官忽悠了。

#6


假设a结构体直接复制个b成立
……这个假设怎么成立的。

#7


b.e应该不变吧。

貌似考直接将基类对象直接赋值给派生类对象。

#8


引用 6 楼 xiaoqiao_82 的回复:
假设a结构体直接复制个b成立
……这个假设怎么成立的。


你应该理解面试官总会想出一些牛逼的问题

#9


我怎么也觉得应该是0啊……还写了个程序看了下:
#include <iostream>
using namespace std;
struct A{
    int x;
    int y;
    char z;
    char w;
}a;

struct B{
    int x;
    int y;
    char z;
    char w;
    char e;
}b;

int main()
{
    a.x = 1;a.y = 2;a.z = 3;a.w = 4;
    b.x = 1;b.y = 2;b.z = 3;b.w = 4;b.e = 5;
    int sizeA = sizeof(a);
    int sizeB = sizeof(b);
    cout << sizeA << endl;
    cout << sizeB << endl;
    return 0;
}

断点打在第24行,停下来以后看内存是这个样子的:
00401321 call   0x4133f0 <__main>
00401326 movl   $0x1,0x474008(a.x------4B)
00401330 movl   $0x2,0x47400c(a.y------4B)
0040133A movb   $0x3,0x474010(a.z------1B)
00401341 movb   $0x4,0x474011(a.w------1B)
00401348 movl   $0x1,0x474014(b.x------4B)
00401352 movl   $0x2,0x474018(b.y------4B)
0040135C movb   $0x3,0x47401c(b.z------1B)
00401363 movb   $0x4,0x47401d(b.w------1B)
0040136A movb   $0x5,0x47401e(b.e------1B)
00401371 movl   $0xc,0x18(%esp)
00401379 movl   $0xc,0x1c(%esp)
并且在win32平台下a和b的大小都是12B,a填充了两个字节:0x474012和0x474013位置,b填充一个字节:0x47401f,那么如果可以做复制操作的话,并假定这个复制是简单的内存块复制,这样应该是将a所占的内存空间覆盖到b的内存空间,从而b.e位置是0x474012的内容,
0x474012: 00 00 01 00 00 00 02 00|00 00 03 04 05 00 00 00    ................
0x474022: 00 00 00 00 00 00 00 00|00 00 00 00 00 00 00 00    ................

可以看到a的两个填充字节都是填充0的,所以b.e也应该变成0啊……果然我也要被面试官鄙视了么。
但是这个复制的假定并不知道到底是怎么样实现的,而且不同的平台是不是也不一定就填充0,但这样的话就不会说是有确定的值了……想不明白,同求大神解惑!

#10


填充值不一定是0
面试官2b不解释

#11


能转换么,俩不同对象,你的值是无法确定的

#12


没啥意义的假设

#13


#include <stdio.h>
struct A {
     int a;
     int b;
     char c;
     char d;
} a;
struct B {
     int a;
     int b;
     char c;
     char d;
     char e;
} b;
int main() {
    a.a=1;  a.b=2; a.c=3; a.d=4;
    b.a=1;  b.b=2; b.c=3; b.d=4; b.e=5;
    b = *(struct B *)&a;
    printf("b.e==%d\n",b.e);
    return 0;
}
//b.e==0
//

#14


如果a是全局变量,那么b.e=0
如果a是局部变量,那么b.e是未知的(a对齐的那两个字节没有被初始化)

#1


他想知道什么呢,要成立,无非添加隐式转换,或者重载=操作符啥的,想让他=多少就=多少啊。要么就是想考你内存对齐了,这两个结构体占用内存一样的。关键还要看怎么假设他成立的吧,请楼下高人解答 c++一道假设性的面试题,求大神

#2


b.e未知。

在32位系统中对齐到4字节边界的逻辑下,A中四个域都不需要对齐调整,但需要在d后面填充两个字节,以合吃族在A数组类型中,下一个元素依然从4字节边界开始,以保证两个int类型成员正好占据一个32位字。B也一样,需要在e后面填充一个字节。

这样,如果以memcpy的方式把A对象赋值给B对象,e对应的位置正好是A对象中的填充字节,填充字节会是什么数据,这一点很难确定。

#3


引用 1 楼 sublimepan 的回复:
他想知道什么呢,要成立,无非添加隐式转换,或者重载=操作符啥的,想让他=多少就=多少啊。要么就是想考你内存对齐了,这两个结构体占用内存一样的。关键还要看怎么假设他成立的吧,请楼下高人解答 c++一道假设性的面试题,求大神


安在内存对齐补0的话,答案应该是0,但是那人批了我一顿。所以纠结了。

#4


引用 2 楼 u010936098 的回复:
b.e未知。

在32位系统中对齐到4字节边界的逻辑下,A中四个域都不需要对齐调整,但需要在d后面填充两个字节,以合吃族在A数组类型中,下一个元素依然从4字节边界开始,以保证两个int类型成员正好占据一个32位字。B也一样,需要在e后面填充一个字节。

这样,如果以memcpy的方式把A对象赋值给B对象,e对应的位置正好是A对象中的填充字节,填充字节会是什么数据,这一点很难确定。


一开始我也是这么想的但是那面试官说有一个确切的值得,所以就又迷茫。
还是我真的不懂啊

#5


引用 2 楼 u010936098 的回复:
b.e未知。

在32位系统中对齐到4字节边界的逻辑下,A中四个域都不需要对齐调整,但需要在d后面填充两个字节,以合吃族在A数组类型中,下一个元素依然从4字节边界开始,以保证两个int类型成员正好占据一个32位字。B也一样,需要在e后面填充一个字节。

这样,如果以memcpy的方式把A对象赋值给B对象,e对应的位置正好是A对象中的填充字节,填充字节会是什么数据,这一点很难确定。


我是不是被面试官忽悠了。

#6


假设a结构体直接复制个b成立
……这个假设怎么成立的。

#7


b.e应该不变吧。

貌似考直接将基类对象直接赋值给派生类对象。

#8


引用 6 楼 xiaoqiao_82 的回复:
假设a结构体直接复制个b成立
……这个假设怎么成立的。


你应该理解面试官总会想出一些牛逼的问题

#9


我怎么也觉得应该是0啊……还写了个程序看了下:
#include <iostream>
using namespace std;
struct A{
    int x;
    int y;
    char z;
    char w;
}a;

struct B{
    int x;
    int y;
    char z;
    char w;
    char e;
}b;

int main()
{
    a.x = 1;a.y = 2;a.z = 3;a.w = 4;
    b.x = 1;b.y = 2;b.z = 3;b.w = 4;b.e = 5;
    int sizeA = sizeof(a);
    int sizeB = sizeof(b);
    cout << sizeA << endl;
    cout << sizeB << endl;
    return 0;
}

断点打在第24行,停下来以后看内存是这个样子的:
00401321 call   0x4133f0 <__main>
00401326 movl   $0x1,0x474008(a.x------4B)
00401330 movl   $0x2,0x47400c(a.y------4B)
0040133A movb   $0x3,0x474010(a.z------1B)
00401341 movb   $0x4,0x474011(a.w------1B)
00401348 movl   $0x1,0x474014(b.x------4B)
00401352 movl   $0x2,0x474018(b.y------4B)
0040135C movb   $0x3,0x47401c(b.z------1B)
00401363 movb   $0x4,0x47401d(b.w------1B)
0040136A movb   $0x5,0x47401e(b.e------1B)
00401371 movl   $0xc,0x18(%esp)
00401379 movl   $0xc,0x1c(%esp)
并且在win32平台下a和b的大小都是12B,a填充了两个字节:0x474012和0x474013位置,b填充一个字节:0x47401f,那么如果可以做复制操作的话,并假定这个复制是简单的内存块复制,这样应该是将a所占的内存空间覆盖到b的内存空间,从而b.e位置是0x474012的内容,
0x474012: 00 00 01 00 00 00 02 00|00 00 03 04 05 00 00 00    ................
0x474022: 00 00 00 00 00 00 00 00|00 00 00 00 00 00 00 00    ................

可以看到a的两个填充字节都是填充0的,所以b.e也应该变成0啊……果然我也要被面试官鄙视了么。
但是这个复制的假定并不知道到底是怎么样实现的,而且不同的平台是不是也不一定就填充0,但这样的话就不会说是有确定的值了……想不明白,同求大神解惑!

#10


填充值不一定是0
面试官2b不解释

#11


能转换么,俩不同对象,你的值是无法确定的

#12


没啥意义的假设

#13


#include <stdio.h>
struct A {
     int a;
     int b;
     char c;
     char d;
} a;
struct B {
     int a;
     int b;
     char c;
     char d;
     char e;
} b;
int main() {
    a.a=1;  a.b=2; a.c=3; a.d=4;
    b.a=1;  b.b=2; b.c=3; b.d=4; b.e=5;
    b = *(struct B *)&a;
    printf("b.e==%d\n",b.e);
    return 0;
}
//b.e==0
//

#14


如果a是全局变量,那么b.e=0
如果a是局部变量,那么b.e是未知的(a对齐的那两个字节没有被初始化)