Inspiriert von der Frage Difference in initalizing and zeroing an array in c/c++ ?, entschied ich mich, die Assembly von, in meinem Fall, eine optimierte Version Build für Windows Mobile Professional (ARM-Prozessor, aus dem Microsoft Optimizing Compiler) zu untersuchen. Was ich fand, war etwas überraschend, und ich frage mich, ob jemand meine Fragen in Bezug darauf klären kann.Seltsame Assembly aus Array 0-Initialisierung
Diese beiden Beispiele werden untersucht:
byte a[10] = { 0 };
byte b[10];
memset(b, 0, sizeof(b));
Sie in der gleichen Funktion verwendet werden, so dass der Stapel sieht wie folgt aus:
[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // b[9] (last element of b)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // b[0] = sp + 12 (stack pointer + 12 bytes)
[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // a[9] (last element of a)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // a[0] = sp (stack pointer, at bottom)
Die generierte Assembly mit meinen Kommentaren:
; byte a[10] = { 0 };
01: mov r3, #0 // r3 = 0
02: mov r2, #9 // 3rd arg to memset: 9 bytes, note that sizeof(a) = 10
03: mov r1, #0 // 2nd arg to memset: 0-initializer
04: add r0, sp, #1 // 1st arg to memset: &a[1] = a + 1, since only 9 bytes will be set
05: strb r3, [sp] // a[0] = r3 = 0, sets the first element of a
06: bl memset // continue in memset
; byte b[10];
; memset(b, 0, sizeof(b));
07: mov r2, #0xA // 3rd arg to memset: 10 bytes, sizeof(b)
08: mov r1, #0 // 2nd arg to memset: 0-initializer
09: add r0, sp, #0xC // 1st arg to memset: sp + 12 bytes (the 10 elements
// of a + 2 padding bytes for alignment) = &b[0]
10: bl memset // continue in memset
Nun, es gibt zwei Dinge, die mich verwirrt:
- Was ist der Sinn der Zeilen 02 und 05? Warum geben Sie nicht einfach & a [0] und 10 Bytes zu memset?
- Warum sind die Füllbytes von 0 nicht initialisiert? Ist das nur für das Auffüllen in Strukturen?
Edit: Ich war zu neugierig, um nicht die Struktur Fall zu testen:
struct Padded
{
DWORD x;
byte y;
};
Der Assembler für 0-Initialisierung es:
; Padded p1 = { 0 };
01: mov r3, #0
02: str r3, [sp]
03: mov r3, #0
04: str r3, [sp, #4]
; Padded p2;
; memset(&p2, 0, sizeof(p2));
05: mov r3, #0
06: str r3, [sp]
07: andcs r4, r0, #0xFF
08: str r3, [sp, #4]
Hier sehen wir in 04 Linie, dass eine Polsterung tatsächlich auftreten, da str
(im Gegensatz zu strb
) verwendet wird. Recht?
Keine Ahnung, aber große Frage –
Nun, nach dem Lesen der Kommentare unten, scheint es, dass msvc ist nur nicht sehr konsequent über Null-Speicher. –