ChatGPT解决这个技术问题 Extra ChatGPT

将结构初始化/重置为零/空

struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

我正在填充这个结构,然后使用这些值。在下一次迭代中,我想在开始重用之前将所有字段重置为 0null

我怎样才能做到这一点?我可以使用 memset 还是必须遍历所有成员然后单独执行?


C
Community

使用初始值定义结构的 const 静态实例,然后只要您想重置它,只需将此值分配给您的变量。

例如:

static const struct x EmptyStruct;

这里我依靠 static initialization 来设置我的初始值,但是如果你想要不同的初始值,你可以使用结构初始化器。

然后,每次循环你都可以写:

myStructVariable = EmptyStruct;

@David Heffernan:如果我只想将所有内容重置为 0,这是否比使用 memset 更好?
@hari 我自己更喜欢这种方法。使用 memset 让我感觉很脏。我更愿意让编译器尽可能地担心内存布局。严格来说,memset 的这种使用是不可移植的,但实际上,如果您曾经在任何重要的地方编译过您的代码,我会感到震惊。因此,如果您愿意,您可以安全地使用 memset。
@hari,它在概念上更好,因为您提供了默认初始化值(类似于对象工厂模式。)
@cnicutar 我知道这一点。请注意,我的回答建议不要使用 memset。还要注意关于我在哪里指出使用 memset 作为分配空值的手段的不可移植性的评论。我之前的评论只是指出了一个事实,即 0 位总是对应于浮点零。
@kp11 引用请
J
Jens Gustedt

当您拥有现代 C (C99) 时,这样做的方法是使用复合文字。

a = (const struct x){ 0 };

这有点类似于 David 的解决方案,只是您不必担心声明一个空结构或是否声明它 static。如果您像我一样使用 const,编译器可以在适当的情况下自由地在只读存储中静态分配复合文字。


像所有优化一样,这完全依赖于编译器,因此您必须检查编译器生成的内容。 “通常”在现代编译器上不会,这些可以很好地跟踪初始化并且只做必要的事情,而不是更多。 (在你衡量真正的减速之前,不要认为这些事情是问题。他们通常不是。)
“缺少初始化程序”警告确实是虚假的。 C 标准准确地规定了必须发生的事情,并将 { 0 } 视为默认初始值设定项。关闭该警告,这是虚假的误报。
“const”真的有必要吗?当然,编译器可以适当地优化它,因为它是一个仅用于此分配的文字。
@JensGustedt 这种类型转换真的需要吗?我不能这样写吗?结构 xa = (const){0};
@Patrick,虽然语法相似,但这不是强制转换而是“复合文字”。而且您正在混淆初始化和分配。
u
user411313

比以上所有更好的是使用标准 C 规范进行结构初始化:

struct StructType structVar = {0};

这里都是零位(永远)。


我不认为你可以在每次循环时都这样做
这确实是可行的。但不幸的是,gcc & g++ 抱怨它。 gcc 生成警告,而 g++ 生成错误。我知道 gcc 和 g++ 对此有过错(它们应该遵循标准 C 规范),但是,为了良好的可移植性,必须考虑到这种限制。
@Cyan 您可以在 C++ 中使用 {} 。 gcc 开发人员似乎unsure whether C++ is supposed to support {0},我自己并不熟悉标准的那部分。
@Matthew:是的,实际上,我最终使用了 memset(),因为 {0}{} 存在太多可移植性问题。不确定 C & C++ 标准在这个问题上是明确的并且是同步的,但显然编译器不是。
在这种情况下这会起作用吗? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
t
templatetypedef

在 C 中,使用 memsetstruct 的内存归零是一种常见的习惯用法:

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

从技术上讲,我不认为这是可移植的,因为它假设机器上的 NULL 指针由整数值 0 表示,但它被广泛使用,因为在大多数机器上都是这种情况。

如果您从 C 迁移到 C++,请注意不要在每个对象上都使用此技术。 C++ 仅在没有成员函数和继承的对象上才允许这样做。


C 标准规定 NULL 始终为 0。如果机器设计为预先确定的无效地址不是字面上的 0,则该体系结构的编译器必须在编译期间进行调整。
@KevinM是的,符号“0”总是对应于NULL指针,即使它是全零的;但是如果使用 memset 将这些位设置为零,编译器将无能为力。
“C++ 仅在没有成员函数和继承的对象上才允许这样做。”这是关于该类型是否被视为“普通旧数据”。标准取决于 C++ 语言的版本。
S
Sourav Ghosh

如果你有一个 C99 兼容的编译器,你可以使用

mystruct = (struct x){0};

否则你应该做大卫赫弗南写的,即声明:

struct x empty = {0};

在循环中:

mystruct = empty;

D
Diego Sevilla

您可以将 memset 与结构的大小一起使用:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));

我认为这里不需要演员阵容。是吗?
好吧,我已经习惯了 C++... 好吧,它也可以在 C++ 中工作,所以我不认为它是一种负担。
是的,我说的不够具体。指向 cv 限定 T 的任何指针都可以转换为 cv 限定 void*。任何数据指针,函数指针完全是另一回事。荣誉@Kevin
memset 是一个选项,但是在使用它时,你必须确保写入的内存与第三个参数的大小完全相同,这就是为什么最好参考实际对象的大小,而不是对象的大小你知道当前的类型。 IOW memset (&x_instance, 0, sizeof(x_instance)); 是一个更好的选择。顺便说一句:(void*) 演员表在 C++ 中也是多余的。
(对不起,我错过了照顾这个问题,现在好多了)
A
Archmede

我相信您可以将空集 ({}) 分配给您的变量。

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}

这不是有效的 C,甚至不是 C99。它必须是一个复合文字,就像上面 JensGustedt 的回答一样。
J
Josh Matthews
 struct x myX;
 ...
 memset(&x, 0, sizeof(myX));

我认为 OP 知道如何调用 memset,但问题是这样做是否明智
R
RandomInsano

我询问了工作中的编译器工程师哪个选项更好(memset 与 {0})。他没有给出我的意见,而是将我指向 Compiler Explorer。看看这三个选项是如何编译出来的很有趣:

https://godbolt.org/z/bPfKeG9Yh

这是代码的预览:

// Type your code here, or load an example.
#include "string.h"

struct MyStruct {
    int age;
    int sin;
    char *name;
    int cats;
    char something[64];
};

const struct MyStruct empty_struct = {0};

int test() {
    struct MyStruct blah = {0};
    memset(&blah, 0, sizeof(blah));
    blah = empty_struct;

    blah.age = 99;
    blah.sin = 123456789;
}

编译器根据结构的成员类型对如何将内存归零做出不同的决定。例如,尝试注释掉 something 或选择非 x86 目标。


R
Redee

带 NULL 的 Memset 是危险的函数。

对于大多数简单的数据结构,通过这种方式更好地使用 C++ >>

template<class T>
void Null_MyType(T &obj)
{
    constexpr T o_null = T{};
    obj = o_null;
}

J
JRL

https://i.stack.imgur.com/Xwjhi.png

来自gnu11的惊喜!

typedef struct {
    uint8_t messType;
    uint8_t ax;  //axis
    uint32_t position;
    uint32_t velocity;
}TgotoData;

TgotoData tmpData = { 0 };

没有什么是零。


这并不试图回答“如何将所有字段重置为 0”的问题