为什么要声明仅在C中包含数组的结构?


131

我遇到了一些包含以下内容的代码:

struct ABC {
    unsigned long array[MAX];
} abc;

什么时候使用这样的声明有意义?

Answers:


184

它允许您按值将数组传递给函数,或从函数中按值返回它。

可以通过值传递结构,这与在这种情况下会衰减到指针的数组不同。


1
注意不要使用不超过16或32个字节的数组来执行非内联函数:通过const引用传递它们会更有效,除非被调用者已经需要可以销毁的tmp副本。如果调用/返回没有优化,那么通过值传递一个大到中的数组(数千个字节)是一件很糟糕的事情。
彼得·科德斯

84

另一个优点是,它抽象了大小,因此[MAX]无论您在哪里声明这样的对象,都不必使用所有代码。这也可以通过

typedef char ABC[MAX];

但是然后您遇到了一个更大的问题:您必须意识到这ABC是一个数组类型(即使在声明type变量时看不到该数组类型ABC),否则您会被事实所困扰,这ABC意味着不同的东西在函数参数列表中,而不是在变量声明/定义中。

另一个优点是,该结构允许您以后根据需要添加更多元素,而无需重写大量代码。


45

您可以复制结构并从函数返回结构。

您不能使用数组来执行此操作-除非它是结构的一部分!


26

您可以像这样复制它。

struct ABC a, b;
........
a = b;

对于数组,您需要使用memcpy函数或循环来分配每个元素。


6
(因此它允许使用更简洁的代码-不会对速度造成任何影响,等等)
John Carter

3
这很有用。不幸的是,如果(a == b)!?!那是多么的不一致。对于C ++,它将查找==运算符。在C语言中,它表示“无效的二进制操作数==”。
马特

11

您可以使用struct生成新型数据,例如string。您可以定义:

struct String {
    char Char[MAX];
};

或者您可以创建一个数据列表,您可以通过函数的参数使用它,也可以在方法中返回它。该结构比数组更灵活,因为它可以支持=等某些运算符,并且您可以在其中定义一些方法。

希望对您有用:)


2
基本上,这是C创建类最接近的事情。我喜欢这个答案,因为它最接近指出这一点。
Nate CK

1
C语言中没有这样的方法。C语言中的结构不是简单的旧数据。它有一个=操作符默认(其中其他的答案显示是这样做的原因)的支持,但是这是一个误导,大多适用于C ++,不C.
乔纳森·斯腾

3
@J Sternberg:“方法”只是将子例程与它们所影响的数据“对象”相关的一种思考方式。您当然可以创建在C中对其进行操作的“对象”和“方法”的“类”。该语言只是未正式定义此类对象。如果要在C中创建更好的抽象,则通常将内容填充到struct中是最好的方法。
Nate CK

另外,如果您真的想在C语言中“创建”方法,则可以使用函数指针(是,是,棘手的语法,没有数据保护等)将函数与它们所操作的数据相关联。您必须在第一个参数中传递“ self”(如果需要,您甚至可以将其命名为“ this”),因为在C函数中不会自动创建此指针。当然,这是所有体操,在C ++中,默认情况下会发生类似这样的事情,尽管的确有可能将额外的开销隐藏起来……
BenPen

2

使用这样的a的另一个优点struct是,无论使用什么a ,它都可以强制类型安全struct。特别是如果您有两种类型,这些类型由大小相同的数组组成,用于不同目的,则这些类型将帮助您避免意外使用数组。

如果您没有将数组包装在中struct,则仍然可以typedef为其声明a :这具有以下优点struct:•类型声明一次,•大小自动正确,•代码意图更清晰,•并且代码更易于维护-但是您将失去◦严格的类型安全性,◦复制和返回该类型的值的能力以及◦稍后添加成员而不破坏其余代码的能力。两个typedefS代表给定类型的裸阵列只产生如果它们是不同尺寸的不同类型。此外,如果您使用typedef没有*在一个函数的参数,它相当于char *,大幅降低类型安全。

总结

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113

1

一个结构可以包含数组初始化,复制和fini函数,这些函数模拟了OOP内存管理范例的某些优点。实际上,扩展此概念以编写通用的内存管理实用程序(通过使用sizeof()结构确切地知道要管理多少字节)来管理任何用户定义的结构非常容易。许多用C编写的智能生产代码库都大量使用这些代码,并且除非其范围非常局部,否则通常不使用数组。

实际上,对于嵌入在结构中的数组,您可以在需要访问此数组时执行其他“智能操作”,例如绑定检查。同样,除非数组范围非常有限,否则使用它并在程序之间传递信息是一个坏主意。迟早,您会遇到一些错误,这些错误会使您在晚上醒着,并破坏了周末。


这不能回答为什么可能使用struct包含一个数组的问题。
PJTraill 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.