关于c ++:Vector改变了类的大小

Vector changing the size of class

编辑:尽管这个问题的格式不好,但还是有一个不错的发现。所以,我正在编辑这个问题,以便将来遇到这个问题的访问者能够更好地保存这个问题。

在下面的代码示例中,有人能解释一下为什么在memcpy之后类的大小与预期的不同吗?原因是什么?

这是Ideone上的在线演示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>

using namespace std;

class A
{
    public:
        int a;
        virtual void f1() { cout <<"inside a::f1
"
; }
        A() { a = 1; }
};

class B
{
    public:
        int b;
        virtual void f2() { cout <<"inside b::f2
"
; }
        virtual void f5() { cout <<"inside b::f5
"
; }
        B() { b = 2; }
};

class C : public A, public B
{
    public:
        int c;
        void f1() { cout <<"inside c::f1
"
; }
        void f2() { cout <<"inside c::f2
"
; }

        virtual void f3() { cout <<"inside c::f3
"
; }
        virtual void f4() { cout <<"inside c::f4
"
; }
        C() { c = 3; }
};


int fun()
{
    int a = 1;
    return a * 2;
}

int main()
{
    C c;
    C c2;
    int (*g)() = &fun;

    void (A::*g1)() = &A::f1;
    void (C::*g2)();

    g2 = &C::f1;
    (c.*g2)();

    printf("%p
"
,g2);
    cout << sizeof(g2) << endl;

    g2 = &C::f2;
    (c.*g2)();

    printf("%p
"
, g2);

    // Why is the output 1 here in g++ or visual C++?
    cout << g2;
    // Why is the sizeof returning 8? Please explain.
    cout << sizeof(g2) << endl;

    g2 = &C::f1;
    std::vector<unsigned char> a_vec(sizeof(g2));

    memcpy(&a_vec[0], &g2, sizeof(g2));
    for(size_t i = 0; i < sizeof(g2); ++i)    
    {        
        cout << hex << static_cast<unsigned>(a_vec[i]) <<"";
    }
    cout << endl;

    g2 = &C::f2;
    std::vector<unsigned char> a_vec1(sizeof(g2));
    memcpy(&a_vec1[0], &g2, sizeof(g2));

    for(size_t i = 0; i < sizeof(g2); ++i)    
    {        
        cout << hex << static_cast<unsigned>(a_vec1[i]) <<"";
    }
    cout << endl;

    cout << sizeof(g) <<endl;
    cout << sizeof(g1) <<endl;
    cout << sizeof(g2) <<endl;

    // Why is sizeof(C) printing 14 and not 20 in visual C++?
    // If yes why is this so ?
    cout << sizeof(C) << endl;
    cout << sizeof(c2) << endl;
    cout << (&c) << endl;
    cout << c.a << endl;
    cout << c.b << endl;
    cout << c.c << endl;

    return 0;
}

从上面的代码示例中,我得到的输出是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
inside c::f1
0x1
8
inside c::f2
0x5
18
1 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0
4
8
8
14
14
0xbffe375c
1
2
3

以下是我的问题:

百万千克1

为什么输出EDOCX1 1在G++或VisualC++中?

cout << g2;

号百万千克1百万千克1

为什么sizeof返回8?请解释一下。

cout << sizeof(g2) << endl;

号百万千克1百万千克1

为什么在Visual C++中EDCOX1×4打印EDOCX1 5?EDCX1 6?如果是,为什么是这样?

cout << sizeof(C) << endl;

号百万千克1


为什么sizeof返回8。请解释一下?

1
cout <<sizeof(g2)<<endl;

返回8,因为g2是指针,环境中指针的大小为8。

为什么输出EDOCX1 3在G++或VisualC++中?

1
cout << g2;

<< operator没有接受指针的重载版本。所以指针被转换为bool类型,值为1,cout打印它。

C++标准允许这样做:

C++ 03标准4.12布尔转换

1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.

为什么EDCOX1〔6〕在Visual C++中打印EDCOX1×7,而不是EDOCX1×8?

1
cout<<sizeof(C)<<endl;

它以十六进制正确显示C的大小(14 in hex==20 in decimal)。这是因为您以前使用了hexI/O管理器来打印地址。

1
cout<<dec<<sizeof(C)<<endl;

将再次将I/O操纵器设置为十进制模式,它将按预期输出20

关于printf和类型安全:

printf不是类型安全的,当使用printf时,用户有责任向其传递正确的formart描述符和数据类型。如果存在不匹配,则将发生未定义的行为。未定义的行为意味着程序可能崩溃或显示任何奇怪的行为。

printf("%p
", g2 );

是未定义行为的示例,格式描述符和数据类型不匹配。请注意,编译器确实对此提出了抱怨,您应该始终注意并检查编译器发出的警告。

warning: format ‘%p’ expects type ‘void*’, but argument 2 has type ‘void (C::*)()’


给定类型的sizeof的结果永远不会改变。(至少对于一个遵守C++程序。G++,我相信,支持C++中的VLAs,作为一个扩展名和sizeof包含VLA的对象可能会更改。)关于你的明确问题:

1
2
printf("%p
"
, g2 );

是未定义的行为。您正在将指向成员的指针传递给输出格式化程序,它需要一个void*。(G++将对此发出警告,i相信,至少有某些选择。)你可能会任何事情(包括程序崩溃)。指向成员的指针不是void*,不能转换为void*

1
cout << g2;

我不敢相信这是真的。

1
cout << sizeof(g2) << endl;

sizeof(g2)返回8,因为这是指向成员的指针的大小在你的系统上。

1
cout << sizeof(C) << endl;

打印14,因为这是类型为的对象的十六进制大小系统上的C。换句话说,sizeof(C)是20。既然你已经设置hex的输出,不重置,输出为十六进制。