动态调整字符数组大小

发布于 2024-08-20 05:08:02 字数 1959 浏览 4 评论 0原文

在我的应用程序中,我定义了一个字符数组,它可以采用三个选项之一:“okay”、“high”、“low”,然后将其通过串行端口发送到远程设备。我目前的数组大小可以容纳 4 个字符的单词加上回车符和换行符,但是当我必须发送“低”时,我在字符串中得到一个空字符,我担心这会混淆主机终端。

switch case 语句的数组定义

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

    }

当我需要发送“低”时,任何人都可以建议一种好方法,将数组动态调整为短一个字符?

谢谢

In my application, I have a char array defined which can take one of three options: "okay", "high", "low" which are then sent down a serial port to a remote device. I currently have the array sized to take the 4 character words plus carriage return and line feed, but when I have to send "low" I get a null character in the strings, which I am concerned would confuse the host terminal.

array definition

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'};     

sample of switch case statement:

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

This is the struct which makes the message string to send

    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;

and this sends the message

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

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

    }

Would anyone be able to suggest a good approach to dynamically size the array to one character shorter when I need to send "low"?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

轻拂→两袖风尘 2024-08-27 05:08:02

我认为不需要动态大小的数组。 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 这里并不完全是“动态的”,但其中字符串的长度根据数据而变化,这可能就是您想要的。或者也许我仍然误解了这三个字符数组的作用。

在我看来,过度复制字符串只会带来复杂性。通过指针引用它们,直到最后一刻,当您的消息被组装时,您可以最大限度地减少代码中必须获得正确缓冲区大小的位置的数量。

I don't think a dynamically sized array is called for. There are two ways in C literally to dynamically size an array: allocate it with malloc or similar; or use C99 VLAs. But in this case where you have strings of different lengths, surely the important point is to write the correct bytes in the correct order? Personally I'd prefer something like this, maybe:

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

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

You don't have to call strlen, necessarily, you could store the lengths in another array. But even on the tiniest embedded device, counting to 6 takes very little time compared with sending serial data.

Of course I'm assuming that whatever function you call to actually send the data, takes a pointer and a length. But if it doesn't, I don't see how a dynamically sized array helps either.

I think the general problem here which makes it difficult to answer the question, is that you don't really say what the "size" of your array is, or why it has anything to do with the number of bytes actually written to the serial port.

Edit: with your additional explanation, the key thing seems to be this struct that the three individual strings are "passed into". Not sure what passing a string into a struct means. If it currently looks like this:

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

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

Then maybe it would be better to do this:

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

Then send the struct using strlen(msg). msg isn't exactly "dynamic" here, but the length of the string in it varies according to the data, which might be what you want. Or maybe I'm still misunderstanding the role of these three char arrays.

Copying the strings more than necessary just seems to me to introduce complications. Refer to them by pointer until the last possible moment, when your message is assembled, and you minimise the number of places in your code where you have to get buffer sizes right.

请帮我爱他 2024-08-27 05:08:02

“然后将 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() 字节。

"The status_char arrays are then passed to a struct, which is then sent using a send routine."

Be very careful doing this, depending on how you code it you can get all kinds of junk in there. Remember in C the compiler can pad structs however it pleases.

As a side note, your string buffers are too short to hold a string correctly. With 4 character + CR + LF you need a buffer of 7 characters as you need to store the null terminator '\0'. If you do not do this, do not use any 'str' functions as you are not dealing with proper C strings, all your going to do is create an issue further down the road when someone goes to read this/make a change and finds out after copying a str around your hacking off the null termination (strcopy is copying "low\0" into your buffer, your apparently tossing /r/n onto the end somewhere else for some reason) use memcpy.

Onto a solution:

Why are you copying these string around at all? Why not just send an indication to your send function to tell it what it should send and just have the string statically allocated?

You could create an enum with values for (E_LOW,E_OKAY,E_HIGH), just send in 3 enums to a send function and have it store the actual strings to send as static variables locally. If space is an issue you could use bit flags instead of an enum.

Your send function just needs to copy the string value a byte at a time into the send buffer and send strlen() bytes.

满身野味 2024-08-27 05:08:02

我在这里错过了什么吗?发送例程应该只对字符串使用 strlen(),以便它只发送缓冲区中的数据。

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

Am I missing something here? The send routine should just use strlen() on the string so it only sends the data in the buffer.

serWrite( mod1_status, strlen( mod1_status));
serWrite( "\r\n", 2);
笑梦风尘 2024-08-27 05:08:02

您有几个选项可供选择:

  1. 如果选项是预定义的,您为什么要发送文本?
    您可以只发送 ID。
  2. 通常,除了极少数情况外,协议消息的长度不是固定的。
    长度第一,消息第二,
    CRC第三。
  3. 用空格填充空的字符数组空间并修剪另一侧的字符串。
    不是一个选择,我没有写这个。

You got few options to choose from:

  1. Why you are sending the text if the options are predefined?
    You could send just the ID.
  2. Normally, protocol messages are not fixed length except some rare cases.
    Length first, message second,
    CRC third.
  3. Fill empty char array space with spaces and trim the string on the other side.
    Not an option, I did not wrote this.
甜嗑 2024-08-27 05:08:02

通过截断数组的“头”。

假设您有 char Words[5](或 6 - 用于保存“\r\n”)。

因此,如果是“okay”和“high”,则从第一个元素 - words 开始发送 words 的内容,如果是 low,则从第二个元素开始发送内容:字数 + 1

编辑:当然,在这种情况下,您应该从 words[1] 开始编写“low”,而不是从 words[0] 开始。

By truncating "head" of array.

Suppose you have char words[5] (or 6 -- to hold "\r\n").

So in case of "okay" and "high" you send content of words starting from first element -- words, and in case of low just send content starting from second one: words + 1.

EDIT: of course in this case you should write "low" starting from words[1], not words[0].

我不会写诗 2024-08-27 05:08:02

我想看看你对 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。除非你声明它们都比我少 1,并且当你执行 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));

编辑:哎呀我想这个问题已经很老了。哦,好吧,我会留下答案,以防它对你有用。

I'd like to see your definition of MsgStatus_on.

I'm betting you have something like this:

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;

And then my guess is that you're doing a straight byte pointer when you call USARTWrite, like so:

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

If this is the case then it's copying the extra byte in your buffer. In fact it should be putting extra \0's on all of your char arrays. Unless you declared all of them one less than I did and you're actually overrunning your arrays when you do the strcpy(). It's not causing you problems because you then set the overrun memory in the next statement.

An alternative option could be to use 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);

Then call:

USARTWrite (message, strlen(message));

EDIT: Oops I guess this question is quite old. Oh well, I'll leave the answer in case it's useful to you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文