将数组及其长度变量包装在 C 中的结构中是否是最佳实践?

发布于 2024-07-15 06:20:09 字数 352 浏览 7 评论 0原文

我很快就会开始在操作系统课程中使用 C,并且正在阅读使用 C 的最佳实践,以便减少以后的麻烦。

这一直是我关于数组的第一个问题,因为它们很容易搞砸。

将数组及其关联变量(包含其长度)捆绑在结构中是否是一种常见的做法?

我从未在书中看到过它,通常他们总是将两者分开或使用类似 sizeof(array[]/array[1]) 之类的处理。

但是,通过将两者包装到一个结构中,您可以通过值和引用传递结构,除非使用指针,否则您无法真正对数组执行此操作,在这种情况下,您必须再次跟踪数组长度。

我开始使用 C,所以上面的内容可能是严重错误的,我还是一名学生。

干杯, 凯.

I will begin to use C for an Operating Systems course soon and I'm reading up on best practices on using C so that headaches are reduced later on.

This has always been one my first questions regarding arrays as they are easy to screw up.

Is it a common practice out there to bundle an array and its associated variable containing it's length in a struct?

I've never seen it in books and usually they always keep the two separate or use something like sizeof(array[]/array[1]) kind of deal.

But with wrapping the two into a struct, you'd be able to pass the struct both by value and by reference which you can't really do with arrays unless using pointers, in which case you have to again keep track of the array length.

I am beginning to use C so the above could be horribly wrong, I am still a student.

Cheers,
Kai.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

温暖的光 2024-07-22 06:20:09

是的,这是 C 语言中的一个很好的实践。将相关值包装到包含结构中是完全符合逻辑的。

我会走得更远。 永远不要直接修改这些值也将有助于您的目的。 相反,在结构体中编写将这些值作为一对起作用的函数,以更改长度和更改数据。 这样您就可以添加不变检查,并且也使其非常容易测试。

Yes this is a great practice to have in C. It's completely logical to wrap related values into a containing structure.

I would go ever further. It would also serve your purpose to never modify these values directly. Instead write functions which act on these values as a pair inside your struct to change length and alter data. That way you can add invariant checks and also make it very easy to test.

网白 2024-07-22 06:20:09

当然,你可以这样做。 不确定我是否将其称为最佳实践,但是让 C 相当基本的数组更易于管理无疑是一个好主意。 如果您需要动态数组,则几乎需要将簿记所需的各个字段分组在一起。

有时在这种情况下您有两种大小:一种是当前大小,另一种是已分配大小。 这是一种权衡,您可以用更少的分配来换取一定的速度,但会付出一些内存开销。

很多时候,数组仅在本地使用,并且具有静态大小,这就是为什么 sizeof 运算符可以如此方便地确定元素的数量。 顺便说一句,您的语法与此略有不同,通常如下所示:

int array[4711];
int i;

for(i = 0; i < sizeof array / sizeof *array; i++)
{
  /* Do stuff with each element. */
}

请记住 sizeof 不是函数,并不总是需要括号。

编辑:一个与您所描述的完全一样的包装示例是GArray 类型由 glib。 声明的用户可见部分正是您所描述的:

typedef struct {
  gchar *data;
  guint len;
} GArray;

程序应尽可能使用提供的 API 来访问数组,而不是直接访问这些字段。

Sure, you can do that. Not sure if I'd call it a best practice, but it's certainly a good idea to make C's rather rudimentary arrays a bit more manageable. If you need dynamic arrays, it's almost a requirement to group the various fields needed to do the bookkeeping together.

Sometimes you have two sizes in that case: one current, and one allocated. This is a tradeoff where you trade fewer allocations for some speed, paying with a bit of memory overhead.

Many times arrays are only used locally, and are of static size, which is why the sizeof operator is so handy to determine the number of elements. Your syntax is slightly off with that, by the way, here's how it usually looks:

int array[4711];
int i;

for(i = 0; i < sizeof array / sizeof *array; i++)
{
  /* Do stuff with each element. */
}

Remember that sizeof is not a function, the parenthesis are not always needed.

EDIT: One real-world example of a wrapping exactly as that which you describe is the GArray type provided by glib. The user-visible part of the declaration is exactly what you describe:

typedef struct {
  gchar *data;
  guint len;
} GArray;

Programs are expected to use the provided API to access the array whenever possible, not poke these fields directly.

拥抱影子 2024-07-22 06:20:09

有三种方法。

  1. 对于静态数组(不是动态分配的,也不是作为指针传递的),大小在编译时就知道,因此您可以使用 sizeof 运算符,如下所示:sizeof(array)/sizeof(array[0] )
  2. 使用终止符(最后一个数组元素的特殊值,不能用作常规数组值),如空终止字符串
  3. 使用单独的值,作为结构成员或独立变量。 这并不重要,因为所有使用数组的标准函数都采用单独的大小变量,但是将数组指针和大小连接到一个结构中将提高代码的可读性。 我建议为您自己的功能使用更清晰的界面。 请注意,如果按值传递结构,被调用的函数将能够更改数组,但不能更改大小变量,因此传递结构指针将是更好的选择。

There are three ways.

  1. For static array (not dynamically allocated and not passed as pointer) size is knows at compile time so you can used sizeof operator, like this: sizeof(array)/sizeof(array[0])
  2. Use terminator (special value for last array element which cannot be used as regular array value), like null-terminated strings
  3. Use separate value, either as a struct member or independent variable. It doesn't really matter because all the standard functions that work with arrays take separate size variable, however joining the array pointer and size into one struct will increase code readability. I suggest to use to have a cleaner interface for your own functions. Please note that if you pass your struct by value, called function will be able to change the array, but not the size variable, so passing struct pointer would be a better option.
路还长,别太狂 2024-07-22 06:20:09

我想说这是一个很好的做法。 事实上,它已经足够好了,在 C++ 中,他们已经将它放入标准库中,并将其称为 vector。 每当您在 C++ 论坛中谈论数组时,您都会收到大量建议使用 vector 的回复。

I'd say it's a good practice. In fact, it's good enough that in C++ they've put it into the standard library and called it vector. Whenever you talk about arrays in a C++ forum, you'll get inundated with responses that say to use vector instead.

木緿 2024-07-22 06:20:09

我不认为这样做有什么问题,但我认为通常不这样做的原因是因为这种结构会产生开销。 出于性能原因,大多数 C 都是裸机代码,因此通常会避免抽象。

I don't see anything wrong with doing that but I think the reason that that is not usually done is because of the overhead incurred by such a structure. Most C is bare-metal code for performance reasons and as such, abstractions are often avoided.

咋地 2024-07-22 06:20:09

我也没有在书上看到太多这样的事情,但我已经做了同样的事情有一段时间了。 将这些东西“打包”在一起似乎是有意义的。 例如,如果您需要从方法返回分配的数组,我发现它特别有用。

I haven't seen it done in books much either, but I've been doing the same the same thing for a while now. It just seems to make sense to "package" those things together. I find it especially useful if you need to return an allocated array from a method for instance.

东走西顾 2024-07-22 06:20:09

对于公共 API,我会将数组和大小值分开。 这就是我所知道的大多数(如果不是全部)c 库的处理方式。 你如何在内部处理它完全取决于你。 因此,使用结构加上一些帮助函数/宏来为您完成棘手的部分是一个好主意。 重新思考如何插入一个项目或删除一个项目总是让我头疼,所以这是一个很好的问题根源。 一次性解决这个问题并且是通用的,可以帮助您从一开始就发现错误。 动态和通用数组的一个很好的实现是 kvec

For public API I'd go with the array and the size value separated. That's how it is handled in most (if not all) c library I know. How you handle it internally it's completely up to you. So using a structure plus some helper functions/macros that do the tricky parts for you is a good idea. It's always making me head-ache to re-think how to insert an item or to remove one, so it's a good source of problems. Solving that once and generic, helps you getting bugs from the beginning low. A nice implementation for dynamic and generic arrays is kvec.

瀞厅☆埖开 2024-07-22 06:20:09

我从来没有见过这样做,但我已经有十多年没有做过操作系统级别的工作了......:-) 乍一看似乎是一个合理的方法。 唯一需要关心的是确保大小在某种程度上保持准确......根据需要计算就没有这个问题。

I've never seen it done that way, but I haven't done OS level work in over a decade... :-) Seems like a reasonable approach at first glance. Only concern would be to make sure that the size somehow stays accurate... Calculating as needed doesn't have that concern.

治碍 2024-07-22 06:20:09

如果您使用静态数组,您可以使用 sizeof 运算符访问数组的大小。 如果将其放入结构体中,则可以通过值、引用和指针将其传递给函数。 通过引用和通过指针传递参数在程序集级别上是相同的(我几乎确信这一点)。

但如果使用动态数组,则在编译时不知道数组的大小。 因此,您可以将此值存储在 struct 中,但您也将仅在结构中存储指向数组的指针:

struct Foo {
  int *myarray;
  int size;
};

因此,您可以按值传递此结构,但您真正要做的是将指针传递给 int (指向数组的指针)和 int (大小)的数组)。

在我看来,这不会对你有太大帮助。 plus 中唯一的优点是,将大小和数组存储在一个位置,并且很容易获得数组的大小。 如果您将使用大量动态数组,您可以这样做。 但如果您将使用很少的数组,那么不使用结构会更容易。

If you use static arrays you have access to the size of array using sizeof operator. If you'll put it into struct, you can pass it to function by value, reference and pointer. Passing argument by reference and by pointer is the same on assembly level (I'm almost sure of it).

But if you use dynamic arrays, you don't know the size of array at compile time. So you can store this value in struct, but you will also store only a pointer to array in structure:

struct Foo {
  int *myarray;
  int size;
};

So you can pass this structure by value, but what you realy do is passing pointer to int (pointer to array) and int (size of array).

In my opinion it won't help you much. The only thing that is in plus, is that you store the size and the array in one place and it is easy to get the size of the array. If you will use a lot of dynamic arrays you can do it this way. But if you will use few arrays, easier will be not to use structures.

深海少女心 2024-07-22 06:20:09

考虑到您可以计算数组的长度(以字节为单位,即不是元素的数量),并且编译器会将 sizeof() 调用替换为实际值(它不是函数,对它的调用将由编译器替换为它“返回”的值),那么您想要将其包装在结构中的唯一原因是为了可读性。

这不是常见的做法,如果你这样做了,查看你的代码的人会假设长度字段是一些特殊值,而不仅仅是数组大小。 这是潜伏在你的提案中的危险,所以你必须小心正确地评论它。

considering you can calculate the length of the array (in bytes, that is, not # of elements) and the compiler will replace the sizeof() calls with the actual value (its not a function, calls to it are replaced by the compiler with the value it 'returns'), then the only reason you'd want to wrap it in a struct is for readability.

It isn't a common practice, if you did it, someone looking at your code would assume the length field was some special value, and not just the array size. That's a danger lurking in your proposal, so you'd have to be careful to comment it properly.

躲猫猫 2024-07-22 06:20:09

我认为你问题的这一部分是倒退的:

“但是通过将两者包装到一个结构中,您将能够通过值和引用传递结构,除非使用指针,否则您无法真正对数组执行此操作,其中如果你必须再次跟踪数组长度。”

传递数组时使用指针是默认行为; 就按值传递整个数组而言,这不会给你带来任何好处。 如果您想复制整个数组而不是让它衰减为指针,您需要将数组包装在结构中。 有关更多信息,请参阅此答案:

按值传递数组到递归函数可能吗?

这里有更多关于数组特殊行为的信息:

I think this part of your question is backwards:

"But with wrapping the two into a struct, you'd be able to pass the struct both by value and by reference which you can't really do with arrays unless using pointers, in which case you have to again keep track of the array length."

Using pointers when passing arrays around is the default behavior; that doesn't buy you anything in terms of passing the entire array by value. If you want to copy the entire array instead of having it decay to a pointer you NEED to wrap the array in a struct. See this answer for more information:

Pass array by value to recursive function possible?

And here is more on the special behavior of arrays:

http://denniskubes.com/2012/08/20/is-c-pass-by-value-or-reference/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文