[英]strcpy seems to be messing with previous serial out on Arduino
我一直對char指針,字符串,String和大多數與指針相關的東西有疑問。 也許我太老了;-)
全局聲明:
char * message;
serialOut
是一個非常短的8字符串,一個標識符( X10D
),然后是數據( nnn
),以及空終止符。 我發現通過串行發送的數據在前端被修整,缺少識別符。 在第一次通過時,它將是完整且正確的,但是在隨后的通過中,僅接收到三個數字。
message
是一條調試消息,輸出到屏幕上進行調試。
device
和onOff
正確填充。
函數導致問題:
byte device = btag-X10_TAG_OFFSET;
byte onOff;
char serialOut[8];
memset (serialOut, 0, 8);
if(x10[device - 1]==1){
onOff = 0;
} else {
onOff = 1;
}
x10[device-1]=-2;
sprintf(serialOut, "X10D%02i%i", device, onOff);
Serial.println(serialOut);
strcpy(message, serialOut); // this line appears to 'modify' the previous line
如果我刪除最后一行並將其交換為:
message = serialOut;
前面的串行通信已完成!
如果沒有,則另一端的數據是垃圾(尚未解密,但顯示為不可打印的字符,這就是我設置調試的原因)。
我認為這不可能相關,但是平等似乎可以“解決”問題。
因為message
是指針,所以您必須使其指向某個有效內存。 如果您不這樣做,並且它是一個全局變量,那么它將為零(即指向NULL
),將其復制將導致不確定的行為 。
如果將其分配為指向serialOut
,則可能會出現另一種未定義行為的情況,因為似乎serialOut
是局部變量,並且在返回其定義的函數時它將不在范圍內,從而使message
指向未使用的內存。
兩種明顯的解決方案是使message
成為足夠大的數組以容納您想要復制到其中的任何內容,或者每次在復制到消息之前動態分配/重新分配足夠的空間。
動態分配在AVR上不是一個好主意,不是因為它是8位MCU,而是因為潛在的堆棧堆沖突。 上面的問題是,您有一個全局char *,並且是全局的,它被初始化為NULL
[這是C標准的一部分,您無法對此進行控制,這由最終可執行文件的__do_clear_bss
部分完成]。 在此NULL
指針上執行strcpy()
時,就從地址0開始寫入。現在,如果這是一台x86機器,並且在應用程序級別上工作,則該軟件將因分段錯誤而崩潰。 AVR中沒有內存保護,因此strcpy()
會很樂意開始將字符串復制到RAM中的地址0。 如果使用絕對地址,這將直接進入寄存器文件,這意味着緩存在這些寄存器上的所有變量現在都將被廢棄。 考慮以下測試案例:
#include <string.h>
int main(void) {
char p[] = "hello";
strcpy(0, p);
while(1);
}
編譯為:
-- snip --
00000096 <main>:
-- snip --
a0: cd b7 in r28, 0x3d ; 61
a2: de b7 in r29, 0x3e ; 62
a4: 86 e0 ldi r24, 0x06 ; 6
a6: e0 e0 ldi r30, 0x00 ; 0
a8: f1 e0 ldi r31, 0x01 ; 1
aa: de 01 movw r26, r28
ac: 11 96 adiw r26, 0x01 ; 1
ae: 01 90 ld r0, Z+
b0: 0d 92 st X+, r0
b2: 8a 95 dec r24
b4: e1 f7 brne .-8 ; 0xae <main+0x18>
b6: be 01 movw r22, r28
b8: 6f 5f subi r22, 0xFF ; 255
ba: 7f 4f sbci r23, 0xFF ; 255
bc: 80 e0 ldi r24, 0x00 ; 0
be: 90 e0 ldi r25, 0x00 ; 0
c0: 0e 94 63 00 call 0xc6 ; 0xc6 <strcpy>
-- snip --
000000c6 <strcpy>:
c6: fb 01 movw r30, r22
c8: dc 01 movw r26, r24
ca: 01 90 ld r0, Z+
cc: 0d 92 st X+, r0
ce: 00 20 and r0, r0
d0: e1 f7 brne .-8 ; 0xca <strcpy+0x4>
d2: 08 95 ret
如果使用avr-gcc版本4.8.2完成並使用avr-gcc -O3 -mmcu=atmega168 -o avr.elf avr.c
調用編譯器avr-gcc -O3 -mmcu=atmega168 -o avr.elf avr.c
從AVR指令集手冊中可以看到,st指令說:“間接存儲一個字節,無論是否存在從寄存器到數據空間的位移。對於帶有SRAM的部件,數據空間由寄存器文件,I / O存儲器和內部SRAM組成(對於沒有SRAM的部件,數據空間僅由寄存器文件組成。”
這證實了上述觀點。 顯然,編譯器並不真正知道您是否丟棄了寄存器,並且會很樂意將它們用於其他用途,甚至進一步丟棄它們。 在strcpy()之后讀取它們也會產生問題。 您可以通過創建一個緩沖區(如果需要全局緩沖區)來解決該問題,該緩沖區為char message[8];
。 由於它是一個全局變量,因此所有元素都將自動初始化為0。關於為什么要刪除數據的原因,我將不得不查看更多代碼以確定原因。 不過,最有可能是由於內存損壞。
干杯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.