繁体   English   中英

在内存中顺序写入不同数据类型的值? 或者,具有多种数据类型的数组?

[英]Write values of different data types in sequence in memory? or, Array with multiple data types?

我对使用C语言写书比较陌生。我已经使用在网上和印刷版中发现的资源自学了自己。 这是我在C编程中的第一个实际项目。 一定喜欢在职培训。

我正在用C编写一些在德州仪器C6701数字信号处理器上使用的代码。 具体来说,我正在编写一组通信功能以通过串行端口进行接口。

我参与的项目已有一个用于通过串行端口发送数据的数据包协议。 这是通过将指针移交给要传输的数据及其长度(以字节为单位)来进行的。 我要做的就是将要写入的字节写入内存中的“数组”中(发送器将字节序列复制到缓冲区中并进行发送)。

我的问题与如何最好地格式化要传输的数据有关,我必须发送的数据由几种不同的数据类型(无符号字符,无符号整数,浮点数等)组成。 我无法将所有内容扩展到float(或int),因为我的通信带宽受到限制,并且需要使数据包尽可能小。

我本来想用数组格式化数据,

unsigned char* dataTx[10];
dataTx[0]=char1;
dataTx[1]=char2;
etc...

除非我的所有数据都不是char,有些不是unsigned int或unsigned short,这将起作用。

为了处理short和int,我使用了移位(现在让我们忽略little-endian与big-endian)。

unsigned char* dataTx[10];
dataTx[0]=short1>>8;
dataTx[1]=short1;
dataTx[2]=int1>>24;
dataTx[3]=int1>>16;
etc...

但是,我相信另一种(更好的方法)是使用指针和指针算术。

unsigned char* dataTx[10]
*(dataTx+0) = int1;
*(dataTx+4) = short1;
*(dataTx+6) = char1;
etc...

我的问题最后 )是,哪种方法(移位或指针算术)是更可接受的方法? 另外,运行起来更快吗? (我也有运行时约​​束)。

我的要求:数据要顺序存储在内存中,没有间隙,中断或填充。

我对结构还不了解,还不知道结构是否可以作为解决方案。 具体来说,我不知道结构是否总是按顺序分配内存位置并且没有中断。 我读到一些东西,表明它们分配了8个字节的块,并可能引入了填充字节。

现在,我倾向于使用指针方法。 感谢您阅读这篇长篇文章。

您可能要使用联合数组。

解决问题的最简单,最传统的方法是设置要发送的数据,然后将指向数据的指针传递给传输例程。 最常见的示例是POSIX send()例程:

ssize_t send(int socket, const void *buffer, size_t length, int flags);

对于您的情况,可以简化为:

ssize_t send(const void *buffer, size_t length);

然后使用类似:

send(&int1, sizeof int1);
send(&short1, sizeof short1);

发送出去。 针对您的情况的示例(但很幼稚)实现可能是:

ssize_t send(const void *buffer, size_t length)
{
  size_t i;
  unsigned char *data = buffer;

  for (i = 0; i < length; i++)
  {
     dataTx[i] = data[i];
  }
}

换句话说,使用自动转换为void * ,然后返回到char *以按字节方式访问您的数据,然后将其适当地发送出去。

长的问题,我将尝试较短的答案。

不要继续*(dataTx + 4)= short1; 等等,因为这种方法可能会失败,因为大多数芯片可能只在某些对齐的位置上进行读/写操作。 您可以按16位访问以2对齐的位置,而以32位访问以4对齐的位置,但是举一个例子:“ int32 char8 int32”-第二个int32的位置为(dataTx + 5)-不是4字节对齐,您可能会收到“总线错误”或类似的信息(取决于您将使用的CPU)。 希望你理解这个问题。

第一种方法-如果您声明:

struct
{
    char a;
    int b;
    char c;
    short d;
};

您现在不再麻烦了,因为编译器本身会注意结构对齐。 当然,请阅读有关编译器中与对齐方式相关的选项的信息(如果是gcc,则简称为对齐方式),因为可能存在一个设置,该设置会强制某些结构域进行对齐或对结构域进行打包。 GCC甚至可以定义每个结构的对齐方式(更多内容请参见 )。

另一种方法是使用一些“类似缓冲区的方法”-类似于卡尔·诺鲁姆的回答(我不会重复该回答),但是还考虑了在复制更多数据时使用memcpy()调用(例如long long或string),因为这可能比逐字节复制要快。

通常,您将使用移位方法,因为许多芯片不允许您将4字节整数复制到奇数字节地址(或更准确地说,是从奇数字节地址开始的4字节集合中) )。 这称为对齐。 如果可移植性是一个问题,或者您的DSP不允许未对齐的访问,则需要进行移位。 如果您的DSP因未对齐访问而导致严重的性能下降,则您可能会为此担心。

但是,我不会写出带有代码的代码来对不同类型的代码进行长期修改,如图所示。 我希望使用函数(可能是内联函数)或宏来处理数据的序列化和反序列化。 例如:

unsigned char dataTx[1024];
unsigned char *dst = dataTx;

dst += st_int2(short1, dst);
dst += st_int4(int1, dst);
dst += st_char(str, len, dst);
...

以函数形式,这些函数可能是:

size_t st_int2(uint16_t value, unsigned char *dst)
{
    *dst++ = (value >> 8) & 0xFF;
    *dst   = value & 0xFF;
    return 2;
}

size_t st_int4(uint32_t value, unsigned char *dst)
{
    *dst++ = (value >> 24) & 0xFF;
    *dst++ = (value >> 16) & 0xFF;
    *dst++ = (value >>  8) & 0xFF;
    *dst   = value & 0xFF;
    return 4;
}

size_t st_char(unsigned char *str, size_t len, unsigned char *dst)
{
    memmove(dst, str, len);
    return len;
}

当然,这些功能使代码变得无聊。 另一方面,它们也减少了出错的机会。 您可以决定名称应为st_uint2()而不是st_int2() ,并且实际上,您可以决定长度应为字节(如此处)还是位(如参数类型)。 只要您始终如一且无聊,就可以做。 您也可以将这些功能组合成更大的功能,以打包整个数据结构。

对于现代编译器,可能不需要屏蔽操作( & 0xFF )。 很久很久以前,我似乎记得它们对于避免某些平台上的某些编译器偶尔出现问题是必要的(因此,我的代码可以追溯到1980年代,其中包括这种屏蔽操作)。 所说的平台可能已经安息了,所以就我而言,它们仍然在那里仍然是纯粹的偏执狂。

请注意,这些函数以big-endian顺序传递数据。 这些函数可以在大端和小端机器上“按原样”使用,并且两种类型的数据都可以正确解释,因此,使用此代码,您可以使各种硬件通过网络进行通信,并且没有沟通不畅。 如果您要传递浮点值,则必须多担心导线上的表示形式。 尽管如此,您可能应该以平台无关的格式传输数据,以使芯​​片类型之间的互操作尽可能简单。 (这也是为什么我在类型大小中使用数字的原因;特别是'int'和'long'在不同的平台上可能意味着不同的意思,但是4字节有符号整数仍然是4字节有符号整数,即使您使用不幸-或幸运-足以拥有一台8字节整数的机器。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM