首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C中不同数据类型的连续内存分配?

C中不同数据类型的连续内存分配?
EN

Stack Overflow用户
提问于 2013-04-14 11:35:33
回答 3查看 1.2K关注 0票数 0

我正在尝试组成一个字符串(恰好是char数组),其中包含固定的14个起始字符,并以不同的内容结束。可变位包含2个浮点数和1个32位整数,它们在数组中分别被视为4个逗号分隔的1字节字符。可以通过下面的代码来说明这一点,由于一些显而易见的原因(*char不能赋值给*float),这段代码不能编译。那么,我能做些什么来绕过它呢?

代码语言:javascript
运行
复制
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语言中的结构和联合之类的东西记忆不清,它们严格地保留了变量在“结构”中定义的内存分配顺序。可能是这样的:

代码语言:javascript
运行
复制
typedef struct
{
  char[14] command;
  float *pressure;
  char comma1;
  float *temperature;
  char comma2;
  uint32_t *time_stamp;
  char CR;
}comStr;

这个结构能保证comStr-> command15给我压力的第一个/最后一个字节(取决于字节顺序)吗?或者,有没有其他特殊的结构让我看不到呢?

(注意: comStr-> command15将不会在未来的代码中进行计算,因此这里不需要考虑超过索引边界。这里唯一重要的是内存是否被连续分配,以便从内存地址(comStr->命令)开始持续29个字节的硬件获取恰好得到我想要的字符串。

附注:当我写这篇文章的时候,我想出了一个主意。我能不能只使用memcpy()来实现这个目的;) memcpy有void*类型的参数,希望它能工作!我现在就要试一下!无论如何,stackOverflow万岁!

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-14 12:08:29

这个提议的结构:

代码语言:javascript
运行
复制
typedef struct
{
  char[14] command;
  float *pressure;
  char comma;
  float *temperature;
  char comma;
  uint32_t *time_stamp;
  char CR;
}comStr;

不会帮助你满足你的需求:

这里唯一重要的事情就是内存是否被连续分配,以便从内存地址(comStr->command)开始持续29个字节的硬件读取能够准确地给出我想要的字符串。

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

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

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

现在还不清楚你在找什么。在一个字符串中,只能用4个字节表示非常有限的浮点值范围。如果你正在寻找二进制数据I/O,那么你可以去掉指针和逗号:

代码语言:javascript
运行
复制
typedef struct
{
  char     command[14];
  float    pressure;
  float    temperature;
  uint32_t time_stamp;
}comStr;

如果你想要逗号,那么你必须更加努力:

代码语言:javascript
运行
复制
typedef struct
{
  char     command[14];
  char     pressure[4];
  char     comma1;
  char     temperature[4];
  char     comma2;
  char     time_stamp[4];
  char     CR;
} comStr;

您必须小心地加载数据:

代码语言:javascript
运行
复制
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));

您必须使用一组类似的内存副本进行解包。请注意,您不能在结构上使用简单的字符串操作;在结构的任何或所有pressuretemperaturetime_stamp部分中可能有零字节。

结构填充

代码语言:javascript
运行
复制
#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上的输出:

代码语言:javascript
运行
复制
Size of comStr = 64
command        0
pressure      16
comma1        24
temperature   32
comma2        40
time_stamp    48
CR            56

请注意,在64位计算机上,该结构有多大。每个指针为8字节,并与8字节对齐。

票数 1
EN

Stack Overflow用户

发布于 2013-04-14 11:54:57

在你的问题中涉及到的各种问题。我将尝试解决其中的一些问题。

  • 保证结构中成员的顺序与您声明的顺序相同。但是这里有一个不同的问题-填充。Check this -http://c-faq.com/struct/padding.html和跟随其他链接/问题
  • 下一件事是,你错误地认为像"125“这样的东西是一个整数,或者像"1.25”这样的东西是一个浮点数--它不是--它是一个字符串。即

char *p= "125";

P将不包含0。它将包含'0‘-如果编码是ASCII,那么它将是48。也就是说,p将包含48 &而不是0。p1将包含49,p2将包含52。float的情况与此类似。

相反的情况也会发生。也就是说,如果你有一个地址,并且你把它当作一个char数组-- char数组将不会包含你认为它会包含的浮点数。请尝试此程序查看以下内容

代码语言:javascript
运行
复制
#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]); 
}

对我来说,它打印的是"╪·↓“。这与字符顺序无关。

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

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

如果您试图从给定的字符数组中读取数据,并试图将其拆分为浮点数和逗号等,那么一种方法是sscanf,但对于您的特定字符串格式来说可能比较困难。

票数 1
EN

Stack Overflow用户

发布于 2013-04-15 20:52:17

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

代码语言:javascript
运行
复制
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);

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15995507

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档