0

我正在尝试编写一个包含固定 14 个起始字符并以不同内容结尾的字符串(完全是 char 数组)。可变位包含 2 个浮点数和 1 个 32 位整数,它们将被单独视为数组中的 4 个 1 字节字符,以逗号分隔。它可以通过以下代码来说明,由于某些明显的原因(*char 不能分配给 *float),它无法编译。那么,我能做些什么来绕过它呢?

char *const comStr = "AT+UCAST:0000=0760,0020,0001\r"; // command string

float *pressure;
float *temperature;
uint32_t *timeStamp;

pressure = comStr + 14; // pressure in the address following the '=' in command string

temperature = comStr + 18; // temperature in the address following the 1st ',' in command string

timeStamp = comStr + 22; // time stamp in the address following the 2nd ',' in command string

我对 C 语言中的 struct 和 union 之类的东西有一个不清楚的记忆,它严格保留了在“结构”中定义变量的内存分配顺序。也许是这样的:

typedef struct
{
  char[14] command;
  float *pressure;
  char comma1;
  float *temperature;
  char comma2;
  uint32_t *time_stamp;
  char CR;
}comStr;

这种结构是否保证 comStr-> command[15] 给了我*压力的第一个/最后一个字节(取决于字节序)?或者有没有其他特殊的结构可以瞒着我?

(注意:comStr-> command[15] 不会在以后的代码中进行评估,因此超出索引边界在这里不是问题。这里唯一重要的是内存是否连续分配以便硬件获取持续从内存地址开始的 29 个字节(comStr-> 命令)给了我我想要的字符串)。

ps 在写这篇文章的时候,我想出了一个主意。我可以只使用 memcpy() 吗?) memcpy 有 void* 类型的参数,希望它能工作!我现在要试试!无论如何,所有冰雹stackOverflow!

编辑:我应该让自己更清楚,对于任何误导和误解,我深表歉意!我要构造的字符数组是通过UART逐字节发送的。为此,如果将字符数组的起始存储器地址和长度提供给 DMA 系统,则将使用 DMA 系统将数组自动逐字节传输到发送缓冲区。所以字符数组必须连续存储在内存中。我希望这能让问题更清楚。

4

3 回答 3

1

这个提议的结构:

typedef struct
{
  char[14] command;
  float *pressure;
  char comma;
  float *temperature;
  char comma;
  uint32_t *time_stamp;
  char CR;
}comStr;

不会帮助您满足您的要求:

comStr->command这里唯一重要的是内存是否是连续分配的,以便从内存地址(

请注意,您不能有两个同名的成员;例如,您需要使用comma1comma2。此外,数组维度位于错误的位置。

一个问题是结构中会有填充字节。

另一个问题是指针将保存结构外部的地址(因为结构内部没有任何有效的东西可供它们指向)。

目前尚不清楚你在追求什么。一个字符串中的 4 个字节只能表示非常有限的浮点值范围。如果您追求二进制数据 I/O,那么您可以删除指针和逗号:

typedef struct
{
  char     command[14];
  float    pressure;
  float    temperature;
  uint32_t time_stamp;
}comStr;

如果你想要逗号,那么你将不得不更加努力:

typedef struct
{
  char     command[14];
  char     pressure[4];
  char     comma1;
  char     temperature[4];
  char     comma2;
  char     time_stamp[4];
  char     CR;
} comStr;

您必须仔细加载数据:

struct comStr com;
float         pressure = ...;
float         temperature = ...;
uint32_t      time_stamp = ...;

assert(sizeof(float) == 4);
...
memmove(&com.pressure, &pressure, sizeof(pressure));
memmove(&com.temperature, &temperature, sizeof(temperature));
memmove(&com.time_stamp, &time_stamp, sizeof(time_stamp));

您必须使用一组类似的内存副本解压缩。请注意,您将无法对结构使用简单的字符串操作;pressure在结构的任何或所有,temperaturetime_stamp部分中可能有零字节。


结构填充

#include <stddef.h>
#include <stdio.h>
#include <stdint.h>

typedef struct
{
  char      command[14];
  float    *pressure;
  char      comma1;
  float    *temperature;
  char      comma2;
  uint32_t *time_stamp;
  char      CR;
} comStr;

int main(void)
{
    static const struct
    {
        char    *name;
        size_t   offset;
    } offsets[] =
    {
        { "command",     offsetof(comStr, command)     },
        { "pressure",    offsetof(comStr, pressure)    },
        { "comma1",      offsetof(comStr, comma1)      },
        { "temperature", offsetof(comStr, temperature) },
        { "comma2",      offsetof(comStr, comma2)      },
        { "time_stamp",  offsetof(comStr, time_stamp)  },
        { "CR",          offsetof(comStr, CR)          },
    };
    enum { NUM_OFFSETS = sizeof(offsets)/sizeof(offsets[0]) };

    printf("Size of comStr = %zu\n", sizeof(comStr));
    for (int i = 0; i < NUM_OFFSETS; i++)
        printf("%-12s  %2zu\n", offsets[i].name, offsets[i].offset);

    return 0;
}

Mac OS X 上的输出:

Size of comStr = 64
command        0
pressure      16
comma1        24
temperature   32
comma2        40
time_stamp    48
CR            56

请注意该结构在 64 位机器上的大小。每个指针都是 8 字节,并且是 8 字节对齐的。

于 2013-04-14T04:08:29.167 回答
1

您的问题要涵盖的各种问题。我将对其中的一些问题进行一些尝试。

  • 保证结构中成员的顺序与您声明它们的顺序相同。但是这里有一个不同的问题 - 填充。检查这个 - http://c-faq.com/struct/padding.html并在那里关注其他链接/问题
  • 接下来的事情是你错误地认为像“125”这样的东西是一个整数,或者像“1.25”这样的东西是一个浮点数——它不是——它是一个字符串。IE

    char * p = "125";
    

    p[0] 将不包含 0。它将包含 '0' - 如果编码是 ASCII,那么这将是 48。即 p[0] 将包含 48 而不是 0。p[1] 将包含 49 & p[ 2] 将包含 52。它与浮点数类似。

相反的情况也会发生。即,如果你有一个地址并且你把它当作一个字符数组 - 字符数组将不包含你认为它会的浮点数。试试这个程序看看这个

#include <stdio.h>

struct A
{
    char c[4];
    float * p;
    int i;
};

int main()
{
    float x = 1.25;
    struct A a;
    a.p = &x;
    a.i = 0; // to make sure the 'presumed' string starting at p gets null terminate after the float
    printf("%s\n", &a.c[4]); 
}

对我来说,它打印“╪·↓”。这与字节顺序无关。

  • 在为结构对象赋值时,您需要记住的另一件事 - 您需要记住 comStr.pressure 和 comStr.temperature 是指针。您不能直接为它们赋值。您需要为它们提供现有浮点数的地址或动态分配它们可以指向的内存。

您是否也在尝试创建 char 数组或解析已经存在的 char 数组。如果您正在尝试创建它,那么更好的方法是使用snprintf它来做您想做的事情。snprintf使用类似于printf但打印到 char 数组的格式说明符。您可以通过这种方式创建您的 char 数组。还有一个更大的问题——你打算用你创建的这个 char 数组做什么——这将决定字节序是否与你相关。

如果您尝试从给定的 char 数组中读取并尝试拆分为浮点数和逗号等,那么执行此操作的一种方法将是sscanf但对于您的特定字符串格式可能会很困难。

于 2013-04-14T03:54:57.370 回答
0

最后,我找到了一个简单的方法,但我不知道这种方法是否有任何缺点。我做了:

char commandStr[27];
char *commandHeader = "AT+UCAST:0000=";
float pressure = 760.0;
float temperature = 20.0;
uint32_t timeStamp = 0;

memcpy(commandStr, commandHeader, 14);
commandStr[26] = '\r';

memcpy((void*)(comStr+14), (void*)(&pressure), 4);
memcpy((void*)(comStr+18), (void*)(&temperature), 4);
memcpy((void*)(comStr+22), (void*)(&timeStamp), 4);

此代码是否有任何安全问题或性能问题或其他问题?

于 2013-04-15T12:52:16.683 回答