我有一个自定义结构,我将使用它通过TCP连接发送数据。在这个结构中声明数组的最佳方式是什么?会是吗
typedef struct programData {
int* dataArray;
size_t numberofelements;
} pd;
// ...
pd data = {0};
data.dataArray = malloc(5*sizeof(int));
// put content in array ...
data.numerofelements = 5;
或者是这样:
typedef struct programData {
int dataArray[5];
} pd;
// ...
pd data = {0};
data.dataArray[0] = ...;
// ...
data.dataArray[4] = ...;
出于在C中使用malloc()
的习惯,我做了第一种方法,但不认为数组的内容实际上会传递给连接另一端的客户端,因为dataArray
实际上是指向服务器内存中内存地址的指针。或者send(2)
真的会和它一起发送数组的内容吗?
编辑:由于从我的代码复制粘贴,导致一些不连贯
send
不是用于传输复合数据结构的服务,包括解释指针和连接数据的含义。它是一种用于发送原始字节的服务。使用send
时,必须将数据转换为可以发送的原始字节。接收器必须根据这些字节构造自己的数据结构。这意味着您必须创建一个使用字节表示数据的方案。
当一个结构的原始字节被发送到另一个系统,而接收系统使用这些相同的原始字节来表示一个结构时,数据的最终含义可能会有所不同,原因包括:
- 系统用不同顺序的字节表示对象(如整数)
- 系统在结构中插入不同数量的填充字节,以保持硬件所需或优选的对齐
- 系统对字符或浮点数据使用不同的编码
- 系统上的类型不同,其中一个可以使用两个字节作为
int
,而另一个使用四个 - 一个系统上的指针在另一个系统中是没有意义的,因为它们指向从未传输到另一系统的数据,并且包含与另一系统上的地址布局无关的地址
使用简单的数据结构,可以定义用于传输原始字节的协议,以发送表示数据结构的实际字节。如果发送和接收系统使用相同的硬件和软件,则情况尤其如此。然而,即使在这种情况下,协议也应该明确规定:每个元素有多大,使用了什么数据编码,每个元素中的字节顺序是什么,等等
假设您有简单的数据结构,并使用简单的协议发送表示数据的实际字节,那么在结构中声明数组当然是最简单的。如果数组很小或通常几乎满了,因此存储和传输未使用的数据只会产生少量浪费,那么在结构中声明数组可能是一个很好的解决方案。
如果阵列中所需的数据量变化非常小,那么出于资源效率的考虑,通常最好动态分配阵列。如您的问题所示,该结构可能包含一个指针,该指针用数组数据的地址填充。
当一个结构包含这样的指针时,就不能用send
发送指针(如果不付出额外的努力来提供其解释)。相反,您将需要使用一个或多个send
调用来发送结构中的其他数据,然后您将需要另一个send
调用来发送阵列中的数据。当然,传输数据的协议必须包括一种通信发送的数组元素数量的方式。
还有一个选项混合了数组空间的动态分配和在结构中包含数组:结构的最后一个元素可以是灵活的数组成员。这是一个在结构中声明为Type dataArray[];
的数组。它必须是结构的最后一个元素。它没有内在的大小,但在为结构分配空间时,您会为数组添加额外的空间。在这种情况下,不是具有指向数组的指针的结构,而是该数组跟随存储器中结构的基部分。这样的结构及其数组可以在单个send
调用中发送,前提是提供了上述注意事项:接收系统必须能够正确解释字节,并且必须传达数组的大小。
最佳实践是让项目的需求决定使用哪种方法。根据需要,两者都有明显的优势。
举两个例子:
1)
typedef struct programData {
int dataArray[5];//assuming '*' was a typo
} pd;
2)
typedef struct programData {
int* dataArray;
size_t numberofelements;
} pd;
如果您在运行前就知道大小要求,那么选项1),即更简单的方法,总是首选的。如果不是,那么选项2)是必要的,但有其成本。内存的动态分配增加了代码在错误处理和内存管理方面的复杂性,并确保使用calloc和系列的所有内容在使用时都被释放。
串行化和反串行化建议传输任何一种形式。(并且是选项2所必需的,因为使用了指针。)实现的额外严格性在提高发送内容的可预测性方面带来了好处。