Для тестов использовал приведенный выше пример Сишного кода.
Цитата
U32 *ptr1= &(test_str.field3);
test_str.field1 = 0x11; // ok
test_str.field2 = 0x2233; // ok
test_str.field3 = 0x44556677; // ok
*ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес"
для неупакованной структуры:
Код
struct {
U8 field1;
U16 field2;
U32 field3;
} test_str;
Был сгенерирован следующий код:
Код
28: U32 *ptr1= &(test_str.field3);
29:
0x00000176 4910 LDR R1,[PC,#0x0040]
0x00000178 4A10 LDR R2,[PC,#0x0040]
30: test_str.field1 = 0x11; // ok
0x0000017A 2011 MOV R0,#0x11
0x0000017C 7008 STRB R0,[R1,#0x00]
31: test_str.field2 = 0x2233; // ok
0x0000017E 4810 LDR R0,[PC,#0x0040]
0x00000180 8048 STRH R0,[R1,#0x02]
32: test_str.field3 = 0x44556677; // ok
33:
0x00000182 4810 LDR R0,[PC,#0x0040]
0x00000184 6048 STR R0,[R1,#0x04]
34: *ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес"
0x00000186 2100 MOV R1,#0x00
0x00000188 1C10 ADD R0,R2,#0
0x0000018A 6001 STR R1,[R0,#0x00]
Как видно из листинга Keil дополнил стуктуру padding байтом по адресу test_str+1. И код получился вполне грамотным.
А вот для упакованной структуры....
Код
struct {
U8 field1;
U16 field2;
U32 field3;
} __packed test_str;
0x00000176 4815 LDR R0,[PC,#0x0054]
0x00000178 4B15 LDR R3,[PC,#0x0054]
30: test_str.field1 = 0x11; // ok
0x0000017A 2111 MOV R1,#0x11
0x0000017C 7001 STRB R1,[R0,#0x00]
31: test_str.field2 = 0x2233; // ok
0x0000017E 4915 LDR R1,[PC,#0x0054]
0x00000180 4815 LDR R0,[PC,#0x0054]
0x00000182 7001 STRB R1,[R0,#0x00]
0x00000184 0A09 LSR R1,R1,#8
0x00000186 7041 STRB R1,[R0,#0x01]
32: test_str.field3 = 0x44556677; // ok
33:
0x00000188 4914 LDR R1,[PC,#0x0050]
0x0000018A 4811 LDR R0,[PC,#0x0044]
0x0000018C 7001 STRB R1,[R0,#0x00]
0x0000018E 0A09 LSR R1,R1,#8
0x00000190 7041 STRB R1,[R0,#0x01]
0x00000192 0A09 LSR R1,R1,#8
0x00000194 7081 STRB R1,[R0,#0x02]
0x00000196 0A09 LSR R1,R1,#8
0x00000198 70C1 STRB R1,[R0,#0x03]
34: *ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес"
0x0000019A 2100 MOV R1,#0x00
0x0000019C 1C18 ADD R0,R3,#0
0x0000019E 6001 STR R1,[R0,#0x00] // <-- Тут R0 = 493
Как следствие затираются первые два поля структуры (field1, field2) и младший байт третьего поля, хотя результатом последней строки Сишного кода должно было быть обнуление field3. При чтении значения по указателю *ptr был сделан хитрый трюк:
Код
35: X = *ptr1;
0x000001A0 1C18 ADD R0,R3,#0
0x000001A2 6800 LDR R0,[R0,#0x00]
0x000001A4 6088 STR R0,[R1,#0x08]
Т.о. причитался сохраненный ранее 0.. Вот так дела..
Никакого Warining'a либо ошибки при компиляции выдано не было.
Так что проблема с компилятором действительно имеет место быть! Проверял на keil 3.23, CA 2.32, 2.40, 2.41, 2.42...
Автору ветки большое спасибо еще раз.
Сообщение отредактировал defunct - Aug 7 2006, 21:22