2010-02-05 2 views
0

В моем приложении у меня есть массив символов, который может принимать один из трех вариантов: «okay», «high», «low», которые затем отправляются по последовательному порту на удаленное устройство. Я в настоящее время имеет размер массива, чтобы взять 4 символьных слова плюс возврат каретки и фид строки, но когда мне нужно отправить «низкий», я получаю нулевой символ в строках, что, я думаю, путает терминал хоста.динамический размер массива массива

определение массива

char mod1_status_char[6] = {'0','0','0','0','0','0'};  
char mod2_status_char[6] = {'0','0','0','0','0','0'};  
char mod3_status_char[6] = {'0','0','0','0','0','0'};  

образец переключатель сазе:

void DCOKStatus(uint8_t *ptr_status) 
{ 
    uint8_t status = *ptr_status; 

    switch (status) 
    { 
     case 0x00: 
      strcpy(mod1_status_char, "okay"); 
      strcpy(mod2_status_char, "okay"); 
      strcpy(mod3_status_char, "okay"); 
      break; 
     case 0x10: 
      strcpy(mod1_status_char, "okay"); 
      strcpy(mod2_status_char, "okay"); 
      strcpy(mod3_status_char, "low"); 
      break; 
    } 

Это структура, которая делает строку сообщения для отправки

strcpy(MsgStatus_on.descriptor_msg, "$psu_"); 
    MsgStatus_on.address01 = hex_addr[0]; 
    MsgStatus_on.address02 = hex_addr[1]; 
    MsgStatus_on.space01 = 0x20; 
    strcpy(MsgStatus_on.cmdmsg01, "op_en op1_"); 
    strcpy(MsgStatus_on.statusmsg01, mod1_status_char); 
    MsgStatus_on.space02 = 0x20; 
    strcpy(MsgStatus_on.cmdmsg02, "op2_"); 
    strcpy(MsgStatus_on.statusmsg02, mod2_status_char); 
    MsgStatus_on.space03 = 0x20; 
    strcpy(MsgStatus_on.cmdmsg03, "op3_"); 
    strcpy(MsgStatus_on.statusmsg03, mod3_status_char); 
    MsgStatus_on.CR = 0x0D; 
    MsgStatus_on.LF = 0x0A; 

и это посылает сообщение

void USARTWrite(char *object, uint32_t size) 
{  
    GPIO_SetBits(GPIOB, GPIO_Pin_1); 

    char *byte; 
    for (byte = object; size--; ++byte)                  
    {          
      USART_SendData(USART1,*byte);         

    } 

Может ли кто-нибудь предложить хороший подход к динамическому размеру массива до одного символа короче, когда мне нужно отправить «низкий»?

Благодаря

+0

Непонятно, что именно должен содержать массив. Можете ли вы опубликовать код, показывающий, как определяется и используется массив, или уточнить? –

+0

Почему динамический размер массива? Сделайте строку/массив любым размером, который вы хотите, и напишите свою процедуру вывода, чтобы она остановилась, когда увидит CR/LF (игнорируя лишние символы, оставшиеся в массиве). – bta

+0

Если вы не NULL-завершаете свои строки, вы, вероятно, захотите избежать использования 'strcpy()', поскольку он будет копировать, пока не увидит '' \ 0''. Вместо этого используйте 'strncpy()', чтобы вы могли указать максимальное количество символов для копирования. – bta

ответ

5

Я не думаю, что массив динамически размера называется для. В C буквально есть два пути для динамического размера массива: назначьте его malloc или аналогичным; или использовать VLA C99. Но в этом случае, когда у вас есть строки разной длины, наверняка важным является написать правильные байты в правильном порядке? Лично я предпочел бы что-то вроде этого, может быть:

char * strings[] = {"okay\r\n", "high\r\n", "low\r\n"}; 

serial_send(strings[msg_number], strlen(strings[msg_number])); 

Вы не должны вызывать StrLen, обязательно, вы можете хранить длину в другом массиве. Но даже на самом маленьком встроенном устройстве подсчет до 6 занимает очень мало времени по сравнению с отправкой последовательных данных.

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

Я думаю, что общая проблема здесь, которая затрудняет ответ на вопрос, заключается в том, что вы действительно не говорите, что такое «размер» вашего массива или почему он имеет какое-либо отношение к количеству байтов на самом деле записанный в последовательный порт.

Редактировать: с помощью вашего дополнительного объяснения ключевая вещь кажется такой структурой, что три отдельные строки «переходят в». Не уверен, что передача строки в struct означает. Если в настоящее время выглядит следующим образом:

struct serialmessage { 
    char first[6]; 
    char second[6]; 
    char third[6]; 
}; 

serialmessage msg; 
memcpy(msg.first, mod1_status_char, 6); // etc. 

Тогда, возможно, было бы лучше сделать это:

char *char mod1_status_char; // etc. 

switch(status) { 
    case 0x00: 
     mod1_status_char = strings[0]; // or #define STATUS_OK 0 
     mod2_status_char = strings[0]; 
     mod3_status_char = strings[0]; 
     break; 
    case 0x10: 
     mod1_status_char = strings[0]; 
     mod2_status_char = strings[0]; 
     mod3_status_char = strings[2]; // STATUS_LOW 
}; 

serialmessage msg[3*MAX_STRING_LENGTH+1]; 
strcpy(msg, mod1_status_char); // or use stpcpy if you have it 
strcat(msg, mod2_status_char); 
strcat(msg, mod3_status_char); 

Затем отправить STRUCT с помощью STRLEN (MSG). msg здесь не является «динамическим», но длина строки в нем зависит от данных, которые могут быть такими, какие вы хотите. Или, может быть, я по-прежнему не понимаю роль этих трех массивов символов.

Копирование строк более чем необходимо, просто мне представляется сложным. Обратитесь к ним указателем до последнего момента, когда ваше сообщение собрано, и вы минимизируете количество мест в вашем коде, где вам нужно правильно получить размеры буфера.

+0

Возможно, вы захотите разрешить \ 0 в конце строки. "strlen (строки [msg_number]) + 1" strlen не включает \ 0 в конце строк 'C'. поэтому в зависимости от того, что получает строку на другом конце, может потребоваться отправка \ 0. Возможно, вам также придется рассмотреть способ разобрать сообщение на другом конце, из последовательного потока. может быть, какой-то очень низкий служебный протокол вокруг строк с длиной строки, встроенной в него. Хотя для этой цели вы можете использовать либо завершающий \ r \ n, либо \ 0. – simon

+0

Да, я предполагал, что в последовательном протоколе используется \ r \ n в качестве терминатора, но если это не так, то необходимо включить фактический терминатор (нуль или что-то еще) и его длину. Я также предполагаю, что последовательный протокол негибкий, если он находится под контролем вопрошающего, тогда я бы предположил некоторые изменения. –

+0

Это начинает иметь смысл. У меня нет контроля над протоколом на другом конце ссылки, сообщения заканчиваются , и нет необходимости отправлять \ 0. Я предполагаю, что в определении строки я могу удалить \ r \ n, поскольку они будут вставляться в большую строку. Только одна вещь о структуре msg, что делает [3 * MAX_STRING_LENGTH + 1]? Я определяю max_string_length по всему миру, и зачем умножать на 3? – droseman

0

У вас есть несколько вариантов на выбор:

  1. Почему вы отправляете текст, если параметры предопределены?
    Вы можете отправить только ID.
  2. Обычно сообщения протокола не фиксированы, кроме некоторых редких случаев.
    Длина первая, сообщение второе, CRC третье.
  3. Заполните пустое пространство массива символами с пробелами и обрезайте строку с другой стороны.
    Не вариант, я этого не писал.
+0

1. Массив заполнен из результатов некоторых оптронов на моем оборудовании, например.g portA = 0x30, массив показывает «okay». Это достигается оператором case switch для strcpy строк в массив 2. В спецификации клиента допустимы только эти три сообщения – droseman

0

Усечение «головы» массива.

Предположим, у вас есть char words[5] (или 6 - для удержания "\ r \ n").

Так что в случае «хорошо» и «высокий» вы отправляете содержание words, начиная с первого элемента - words, а в случае низкого просто отправить содержимое, начиная от второго: words + 1.

EDIT: конечно, в этом случае вы должны написать «низкий», начиная с words[1], а не words[0].

+1

Указатель на массив ??? За серией к другому процессору? –

+0

Спасибо, текст исправлен. –

1

Я что-то упустил? Процедура отправки должна просто использовать strlen() для строки, поэтому она только отправляет данные в буфер.

serWrite(mod1_status, strlen(mod1_status)); 
serWrite("\r\n", 2); 
+0

Только если для строк добавлены NULL-терминаторы. – bta

3

«Массивы status_char затем передаются в структуру, которая затем отправляется с использованием процедуры отправки».

Будьте очень осторожны, делая это, в зависимости от того, как вы его кодируете, вы можете получить там всевозможные мусор. Помните, что в C компилятор может создавать паттерны, но это радует.

Как боковое примечание, ваши строковые буферы слишком короткие, чтобы правильно держать строку. С 4 символами + CR + LF вам нужен буфер из 7 символов, поскольку вам нужно сохранить нулевой ограничитель '\ 0'. Если вы этого не сделаете, не используйте никакие «str» -функции, поскольку вы не имеете дело с правильными строками C, все, что вы собираетесь сделать, это создать проблему дальше по дороге, когда кто-то читает это/вносит изменения и находит после копирования строки вокруг вашего взлома с нулевым завершением (strcopy копирует «low \ 0» в ваш буфер, ваш явно бросающий/r/n на конец где-то еще по какой-то причине) использует memcpy.

Onto решение:

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

Вы можете создать перечисление со значениями для (E_LOW, E_OKAY, E_HIGH), просто отправить 3 перечисления в функцию отправки и сохранить в нем фактические строки для отправки как статические переменные локально. Если пространство является проблемой, вы можете использовать битовые флаги вместо перечисления.

Ваша функция отправки просто должна скопировать значение строки по байтам за раз в буфер отправки и отправить strlen() байты.

0

Я бы хотел увидеть ваше определение MsgStatus_on.

Держу пари, у вас есть что-то вроде этого:

tyepdef struct { 
    char descriptor_msg[6]; 
    char address01; 
    char address02; 
    char space01; 
    char cmdmsg01[11]; 
    char statusmsg01[6]; 
    char space02; 
    char cmdmsg02[5]; 
    char statusmsg02[6]; 
    char space03; 
    char cmdmsg03[5]; 
    char statusmsg03[6]; 
    char CR; 
    char LF; 
} MsgStatus; 

MsgStatus MsgStatus_on;

И тогда я думаю, что вы делаете прямой указатель байт при вызове USARTWrite, например, так:

USARTWrite ((char *)&MsgStatus_on, sizeof(MsgStatus_on)); 

Если это так, то он копирует дополнительные байты в буфере. На самом деле это должно быть добавление дополнительных \ 0 на все ваши массивы char. Если вы не объявили все из них меньше, чем я, и вы на самом деле обгоняете свои массивы, когда вы выполняете команду strcpy(). Это не вызывает проблем, потому что вы устанавливаете память переполнения в следующем выражении.

Альтернативным вариантом может быть использование Sprintf:

char *message[100] //or some size big enough to hold the whole message. 

sprintf (message, "$psu_%d%d op_en op1_%s op2_%s op3_%s\r\n", 
    address01, address02, mod1_status_char, mod2_status_char, mod3_status_char); 

Тогда звоните:

USARTWrite (message, strlen(message)); 

EDIT: К сожалению, я думаю, этот вопрос довольно старый. Хорошо, я оставлю ответ на случай, если он вам будет полезен.

Смежные вопросы