strcpy, кажется, возится с предыдущим сериалом на Arduino

У меня всегда были проблемы с концепцией указателей на символы, строк, строк и большинства связанных с указателем вещей. Может быть, я слишком стар для этого 😉

объявлено глобально:

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;

предыдущая последовательная связь завершена!

Если у меня нет ни того, ни другого, то данные на другом конце являются мусором (еще не расшифрованы, но отображаются как непечатные символы — вот почему я настраиваю отладку).

Я думаю, что это не может быть связано, но равенство, похоже, решает проблему.

1

Решение

Так как message это указатель, который вы должны указать на некоторую действительную память. Если вы этого не сделаете, и это глобальная переменная, то она будет равна нулю (т. Е. Указывает на NULL) и копирование на него приведет к неопределенное поведение.

если ты назначать это указывать на serialOut вместо этого у вас есть еще один случай неопределенного поведения, так как кажется, что serialOut является локальной переменной, и она выйдет из области видимости, когда функция, определенная в возврате, message указать на неиспользованную память.

Два очевидных решения должны сделать message массив достаточно большого размера, чтобы вместить в него все, что вы захотите скопировать, или динамически выделять / перераспределять достаточно места каждый раз перед копированием в него.

1

Другие решения

Динамическое распределение является плохой идеей для AVR не потому, что это 8-битный MCU, а из-за потенциальных коллизий стека и кучи. Проблема выше в том, что у вас есть глобальный символ *, и, будучи глобальным, он инициализируется NULL [это часть стандарта C, вы не можете это контролировать, это делается __do_clear_bss раздел финального исполняемого файла. В тот момент, когда вы делаете strcpy() на этом NULL Указатель, вы начинаете писать по адресу 0. Теперь, если это был компьютер с архитектурой x86, и вы работали на уровне приложения, программное обеспечение зависало бы из-за ошибки сегментации. В AVR нет защиты памяти, поэтому strcpy() с радостью начнет копировать строку по адресу 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 st инструкция говорит:
«Сохраняет один байт, косвенный с или без смещения из регистра в пространство данных. Для частей с SRAM пространство данных состоит из файла регистра, памяти ввода-вывода и внутренней SRAM (и внешней SRAM, если применимо). Для частей без SRAM, пространство данных состоит только из регистрационного файла. «

что подтверждает вышесказанное. Очевидно, что компилятор на самом деле не знает, что вы уничтожили регистры, и с радостью будет использовать их для других вещей, уничтожая их еще дальше. Чтение с них после strcpy () также приведет к проблемам. Вы можете решить проблему, сделав буфер, если вы хотите, чтобы он был глобальным, как char message[8];, Поскольку это глобальная переменная, все элементы автоматически инициализируются равными 0. Что касается того, почему ваши данные попадают в мусор, я должен был бы увидеть больше вашего кода, чтобы определить, почему. Скорее всего, из-за повреждения памяти.

Приветствия.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector