簡體   English   中英

strcpy似乎與Arduino上的先前串行混亂

[英]strcpy seems to be messing with previous serial out on Arduino

我一直對char指針,字符串,String和大多數與指針相關的東西有疑問。 也許我太老了;-)

全局聲明:

char * message;

serialOut是一個非常短的8字符串,一個標識符( X10D ),然后是數據( nnn ),以及空終止符。 我發現通過串行發送的數據在前端被修整,缺少識別符。 在第一次通過時,它將是完整且正確的,但是在隨后的通過中,僅接收到三個數字。

message是一條調試消息,輸出到屏幕上進行調試。

deviceonOff正確填充。

函數導致問題:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM