динамический размер массива символов - PullRequest
0 голосов
/ 05 февраля 2010

В моем приложении определен массив символов, который может принимать одну из трех опций: «хорошо», «высокий», «низкий», которые затем отправляются по последовательному порту на удаленное устройство. В настоящее время у меня есть размер массива, позволяющий принимать 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);                                 

    }

Кто-нибудь сможет предложить хороший подход для динамического изменения размера массива на один символ короче, когда мне нужно будет отправить "low"?

Спасибо

Ответы [ 6 ]

5 голосов
/ 05 февраля 2010

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

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

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

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

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

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

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

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);

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

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

3 голосов
/ 06 февраля 2010

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

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

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

На решение:

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

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

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

1 голос
/ 05 февраля 2010

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

serWrite( mod1_status, strlen( mod1_status));
serWrite( "\r\n", 2);
0 голосов
/ 13 апреля 2010

Я хотел бы увидеть ваше определение 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 для всех ваших массивов символов. Если вы не объявили все из них на единицу меньше, чем я, и вы на самом деле не используете свои массивы, когда выполняете 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));

РЕДАКТИРОВАТЬ: Ой я думаю, этот вопрос довольно старый. Ну что ж, я оставлю ответ на тот случай, если он пригодится тебе.

0 голосов
/ 05 февраля 2010

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

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

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

РЕДАКТИРОВАТЬ: конечно, в этом случае вы должны написать «низкий», начиная с words[1], а не words[0].

0 голосов
/ 05 февраля 2010

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

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