我的问题是构造函数/析构函数执行优化:PC和AVR(8位)平台之间的执行顺序存在显着差异。
我创建了一个小源来演示它。重要的部分是C类,它在运算符<(<()。
中实例化让我们先看看PC版:
(此处的F类仅用于查看输出中的浮点运算)
#include <iostream>
struct C
{
C()
{
std::cout << "C created" << std::endl;
}
~C()
{
std::cout << "C deleted" << std::endl;
}
};
struct D
{
D & operator<<(float f)
{
C _c;
std::cout << "D << " << f << std::endl;
value = f;
return *this;
}
float value;
};
struct F
{
F(float f):
value(f)
{
std::cout << "F created: " << value << std::endl;
}
operator float()
{
return value;
}
F operator+(float f)
{
std::cout << value << "+" << f << "=" << value+f << std::endl;
return F(value+f);
}
float value;
};
F f1(3.5f);
F f2(4.2f);
D d;
int main()
{
std::cout << "main() started" << std::endl;
d << (f1+f2);
}
我为我的PC编译了它(这个源是在main.cpp中):
g++ -o main -O4 -Wall main.cpp
执行结果如下:
$ ./main
F created: 3.5
F created: 4.2
main() started
3.5+4.2=7.7
F created: 7.7
C created
D << 7.7
C deleted
执行顺序在这里是正确的,一切都按预期进行。
要为AVR(8位系列)编译它,删除了std :: cout调用,并稍微修改了类C:
struct C
{
C()
{
asm("cli");
}
~C()
{
asm("sei");
}
};
struct D
{
D & operator<<(float f)
{
C _c;
value = f;
return *this;
}
float value;
};
float f1(3.5f);
float f2(4.2f);
D d;
int main()
{
d << (f1+f2);
}
它是为AVR(8位系列)编译的:
avr-g++ -o main -O4 -Wall main.cpp
让我们看看主要功能的结果:
00000028 <main>:
28: f8 94 cli
2a: 20 91 68 00 lds r18, 0x0068
2e: 30 91 69 00 lds r19, 0x0069
32: 40 91 6a 00 lds r20, 0x006A
36: 50 91 6b 00 lds r21, 0x006B
3a: 60 91 64 00 lds r22, 0x0064
3e: 70 91 65 00 lds r23, 0x0065
42: 80 91 66 00 lds r24, 0x0066
46: 90 91 67 00 lds r25, 0x0067
4a: 2e d0 rcall .+92 ; 0xa8 <__addsf3>
4c: 60 93 60 00 sts 0x0060, r22
50: 70 93 61 00 sts 0x0061, r23
54: 80 93 62 00 sts 0x0062, r24
58: 90 93 63 00 sts 0x0063, r25
5c: 78 94 sei
5e: 80 e0 ldi r24, 0x00 ; 0
60: 90 e0 ldi r25, 0x00 ; 0
62: 08 95 ret
每个操作都在&#39; cli&#39;之间执行。和&#39; sei&#39;这里,这意味着C类比预期更早地实例化。我希望首先执行添加,并且只在&#39; cli&#39;之间进行分配。和&#39; sei&#39;不知何故,整个表达式被优化为运算符&lt;&lt;()函数。
我尝试创建临时变量和其他技巧,但无法获得预期的行为。不幸的是我不太了解C ++标准, 所以我无法确定它是否是编译器错误或标准允许这样的执行顺序更改。至少我不明白平台之间的区别。
请帮助我如何在AVR平台中获得预期的执行顺序!
我希望这样的事情:
0000002a <main>:
2a: 20 91 68 00 lds r18, 0x0068
2e: 30 91 69 00 lds r19, 0x0069
32: 40 91 6a 00 lds r20, 0x006A
36: 50 91 6b 00 lds r21, 0x006B
3a: 60 91 64 00 lds r22, 0x0064
3e: 70 91 65 00 lds r23, 0x0065
42: 80 91 66 00 lds r24, 0x0066
46: 90 91 67 00 lds r25, 0x0067
4a: 2e d0 rcall .+92 ; 0xa8 <__addsf3>
4c: f8 94 cli
4e: 60 93 60 00 sts 0x0060, r22
52: 70 93 61 00 sts 0x0061, r23
56: 80 93 62 00 sts 0x0062, r24
5a: 90 93 63 00 sts 0x0063, r25
5e: 78 94 sei
60: 80 e0 ldi r24, 0x00 ; 0
62: 90 e0 ldi r25, 0x00 ; 0
64: 08 95 ret
我尝试了g ++版本4.9.2和5.3.0,结果相同。
提前完成,
Gyorgy Kovesdi
增加第一条评论: 全球对象&#39;顺序并不重要,只有类C,它是一个函数的本地,而且它的构造函数只针对这个例子中的f1 + f2之类的操作。 asm指令也不相关,构造函数可以有任何内容,这只是一个例子。