C 中结构体数组的静态初始化

发布于 2024-12-17 00:48:16 字数 665 浏览 0 评论 0原文

我有一个关于 C 中结构数组初始化的问题。谷歌搜索告诉我,很多人都有非常相似的问题,但它们并不完全相同。

本质上,我有一个“memPermissions”类型的全局结构数组,如下所示。 该数组需要在程序执行时将所有“address”和“ownerId”字段初始化为-1。

typedef struct memPermissions {
    int address;
    int ownerId;
} *test;

问题是数组的大小是使用 #define 确定的,所以我不能简单地去:

#define numBoxes 5

struct memPermissions memPermissions[numBoxes] = {
{-1, -1},
...
{-1, -1}
};

我尝试过:

struct memPermissions memPermissions[numBoxes] = {-1, -1};

但自然这只会初始化第一个元素。 (其余均设为0)。想到的唯一解决方案是在某个地方用一个简单的循环来初始化它,但由于该代码将运行的位置的性质,我真的希望这不是我唯一的选择。

有没有办法在没有循环的情况下初始化这个结构数组的所有元素?

干杯, -乔什

I have a question regarding the initialization of an array of structs in C. Googling showed me that a lot of people have had very similar questions, but they weren't quite identical.

Essentially, I have a global array of structs of type "memPermissions" shown below.
This array needs all the "address" and "ownerId" fields to be initialized to -1 upon program execution.

typedef struct memPermissions {
    int address;
    int ownerId;
} *test;

The problem is the array is sized using a #define, so I can't simply go:

#define numBoxes 5

struct memPermissions memPermissions[numBoxes] = {
{-1, -1},
...
{-1, -1}
};

I tried:

struct memPermissions memPermissions[numBoxes] = {-1, -1};

But naturally this only initialized the first element. (The rest were set to 0). The only solution that jumps to mind would be to initialize it with a simple loop somewhere, but because of the nature of where this code will run, I'm really hoping that's not my only option.

Is there any way to initialize all the elements of this array of structs without a loop?

Cheers,
-Josh

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

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

发布评论

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

评论(5

忆梦 2024-12-24 00:48:16

C99 标准添加了各种有用的方法来初始化结构,但没有提供重复运算符(Fortran 一直都有这个操作符 - 但也许这就是它没有添加的原因)。

如果您使用的是足够新的 GCC 版本并且可以使用不可移植的扩展,那么 GCC 会提供一个扩展。在 GCC 8.1.0 手册中 ( §6.27 指定初始化器),它说:

要将一系列元素初始化为相同的值,请编写“[first ... last] = value”。
这是一个 GNU 扩展。例如,

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

如果其中的值有副作用,则副作用只会发生一次,而不是针对范围初始化程序初始化的每个字段。

所以,在你的例子中使用这个:

struct memPermissions memPermissions[numBoxes] =
{
    [0..numBoxes-1] = {-1, -1},    // GCC extension
};

我希望这是在 C 标准中;这会很有帮助的!


如果不使用该机制或其他类似的特定于编译器的机制,您唯一的选择就是循环。对于具有许多字段且值不完全相同的复杂初始值设定项,您可以使用:

#include <string.h>
#include "memperm.h"  // Header declaring your types and variables

static int initialized = 0;
// -2 so the initialization isn't uniform and memset() is not an option
static const struct memPermissions initPermissions = { -1, -2 };
struct memPermissions memPermissions[numBoxes];

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i], &initPermissions, sizeof(initPermissions));
        initialized = 1;
    }
}

您还可以在此处使用 memcpy() - 不存在两个变量重叠的危险。

现在您只需确保在使用数组之前调用 initialize_permissions() - 最好只调用一次。也可能存在特定于编译器的机制来允许这样做。

您可以在 initialize_permissions() 函数中使用局部变量来代替已初始化的静态常量变量 - 只要确保您的编译器不会在每次调用该函数时都对其进行初始化即可。

如果您有 C99 编译器,则可以使用复合文字来代替常量:

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i],&(struct memPermissions){ -1, -2 },
                    sizeof(memPermissions[0]));
        initialized = 1;
    }
}

The C99 standard added all sorts of useful ways to initialize structures, but did not provide a repeat operator (which Fortran has had since forever - but maybe that was why it wasn't added).

If you are using a sufficiently recent version of GCC and you can afford to use a non-portable extension, then GCC provides an extension. In the GCC 8.1.0 manual (§6.27 Designated Initializers), it says:

To initialize a range of elements to the same value, write ‘[first ... last] = value’.
This is a GNU extension. For example,

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

If the value in it has side-effects, the side-effects will happen only once, not for each initialized field by the range initializer.

So, using this in your example:

struct memPermissions memPermissions[numBoxes] =
{
    [0..numBoxes-1] = {-1, -1},    // GCC extension
};

I wish this were in the C Standard; it would be so helpful!


Without using that or other similar compiler-specific mechanisms, your only choice is a loop. For a complex initializer with many fields, not all the same value, you can probably use:

#include <string.h>
#include "memperm.h"  // Header declaring your types and variables

static int initialized = 0;
// -2 so the initialization isn't uniform and memset() is not an option
static const struct memPermissions initPermissions = { -1, -2 };
struct memPermissions memPermissions[numBoxes];

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i], &initPermissions, sizeof(initPermissions));
        initialized = 1;
    }
}

You can also use memcpy() here - there is no danger of the two variables overlapping.

Now you just need to ensure that initialize_permissions() is called before the array is used - preferably just once. There may be compiler-specific mechanisms to allow that, too.

You could use a local variable in the initialize_permissions() function in place of the initialized static constant variable - just be sure your compiler doesn't initialize it every time the function is called.

If you have a C99 compiler, you can use a compound literal in place of the constant:

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i],&(struct memPermissions){ -1, -2 },
                    sizeof(memPermissions[0]));
        initialized = 1;
    }
}
谁人与我共长歌 2024-12-24 00:48:16

您可以编写一个外部程序来传递所需的项目数。该程序应该由您的 Makefile 或等效文件调用。该程序将为您编写一个包含文件,其中包含所需数量的 -1 值以及#define

You can write an external program that is passed the number of items that you want. This program should be called by your Makefile or equivalent. The program will write an include file for you with the required number of -1 values as well as the #define.

开始看清了 2024-12-24 00:48:16

如果您有可用的标准库,则可以将 memsetsizeof(struct memPermissions) * numBoxes 结合使用,用任何统一的字节值填充数组。由于 -1 在许多平台上是 0xFFFFFFFF,因此这可能适合您。

If you have the standard library available, you can use memset combined with sizeof(struct memPermissions) * numBoxes to fill your array with any uniform byte value. Since -1 is 0xFFFFFFFF on many platforms, this might work for you.

心奴独伤 2024-12-24 00:48:16

唯一想到的解决方案是在某处用一个简单的循环来初始化它

恐怕这是该语言中唯一的可能性。在 C 中,您可以显式初始化每个元素、初始化为全零或不初始化。

但是,您可以通过使用 0 来回避该问题,以达到 -1 当前所服务的目的。

The only solution that jumps to mind would be to initialize it with a simple loop somewhere

Which is the only possibility within the language, I'm afraid. In C, you either initialize each element explicitly, initialize to all zeros or don't initialize.

However, you can sidestep the issue by using 0 for the purpose that your -1 currently serves.

相思碎 2024-12-24 00:48:16

如果不使用循环确实很重要,那么您可以做一些相当奇怪的事情,并使用/滥用memset(假设可用)。

NB Memset 可以使用循环来实现,因此它可能没有实际意义。

memset(memPermissions, 0xFF, sizeof(memPermissions)*numBoxes*2*sizeof(int));

结构体的两个成员(即其中两个)都需要时间 2。

这是设计得很糟糕的,因为它取决于结构没有填充或对齐,而编译器可以根据 C 规范自由地这样做。

(在 32 位处理器上使用 -1 通常为 0xFFFFFFFF 表示 2-compliment 负整数,使用 32 位 int。感谢 @ James 指出了这一点。)

尽管在大多数情况下,我怀疑代码会以汇编语言实现为一个小、快速、紧密的循环(x86 的 rep movsd),但除了最简单的情况(numBoxes 的值非常小)。

If it really important to not use a loop, you could do something rather strange, and use/abuse memset assuming that is available.

N.B. Memset may be implemented using a loop, so it may be moot.

memset(memPermissions, 0xFF, sizeof(memPermissions)*numBoxes*2*sizeof(int));

The times 2 is needed for both members of the struct (i.e. two of them).

This is poorly designed in that it depends that the struct is not padded or aligned, which the compiler is free to do so as per the C specifications.

(Utilizing that -1 is typically 0xFFFFFFFF for 2-compliment negative integers on 32-bit processors, with 32-bit int. Kudos to @James for pointing this out.)

Though I would suspect in most cases that the code would be implemented as a small, fast, tight loop (rep movsd for x86) in assembly language in all but the most trivial of cases (very small values of numBoxes).

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