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

时间:2011-08-24 21:18:52

标签: c arrays pointers ti-dsp

我在C语言写作方面相对较新。我自学了自己使用的在线和印刷资源。这是我在C编程中的第一个真正的项目。一定要喜欢在职培训。

我正在用C语言编写一些用于德州仪器C6701数字信号处理器的代码。具体来说,我正在编写一组通过串口连接的通信功能。

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

我的问题涉及如何最好地格式化要传输的数据,我必须发送的数据由几种不同的数据类型组成(unsigned char,unsigned int,float等...)。我无法将所有内容扩展到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个字节的块,并可能引入填充字节。

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

4 个答案:

答案 0 :(得分:0)

您可能想要使用一组联合。

答案 1 :(得分:0)

处理问题最简单,最传统的方法是设置要发送的数据,然后将指向数据的指针传递给传输例程。最常见的例子是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 *以获取对数据的逐字节访问权限,然后将其适当地发送出去。

答案 2 :(得分:0)

很长的问题,我会尝试更短的答案。

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

第一种方式 - 你可以尝试使用struct,如果你声明:

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

你现在已经没有麻烦,因为编译器本身会关注结构对齐。当然,请阅读编译器中与对齐相关的选项(如果这是gcc,那么这简称为对齐),因为可能有一个设置会强制某些struct字段对齐或打包struct字段。 GCC甚至可以定义每个结构的对齐(更多here)。

另一种方法是使用一些“缓冲式方法” - 类似于Carl Norum的回答帖子(我不会重复那个答案),还考虑在更多数据时使用memcpy()调用被复制(例如long long或string),因为这可能比逐字节复制更快。

答案 3 :(得分:0)

通常你会使用位移方法,因为许多芯片不允许你将一个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)。很久以前,我似乎记得他们有必要避免某些平台上某些编译器的偶然问题(因此,我的代码可以追溯到20世纪80年代,包括这种掩蔽操作)。所说的平台可能已经安静地休息了,所以我可能是纯粹的偏执狂,他们(仍然)在那里。

请注意,这些函数以big-endian顺序传递数据。这些函数可以在big-endian和little-endian机器上“按原样”使用,并且数据将在两种类型上正确解释,因此您可以使用此代码通过线路进行各种硬件通信,并且将会有没有误传。如果要传递浮点值,则必须更加关注线上的表示。尽管如此,您可能应该以平台中立格式传输数据,以便芯片类型之间的互通尽可能简单。 (这也是我使用带有数字的类型大小的原因;'int'和'long'特别是在不同平台上可能意味着不同的东西,但4字节有符号整数仍然是一个4字节有符号整数,即使你是不幸的 - 或幸运的是 - 足以拥有一个8字节整数的机器。)