繁体   English   中英

如何初始化 C 中的结构中的所有对象,就像构造函数初始化 C++ 中的所有 class 对象一样?

[英]How can I initialize all objects from a struct in C the way constructor initializes all class objects in C++?

例如,假设我定义了一个 struct emp_t 然后,我希望从该结构创建的所有员工(对象)的 ID = 0、名称 =“空字符串”和薪水 = 0。这可能吗?

struct employee
{
    int id;
    char name [30];
    int salary;
};
typedef struct employee emp_t;

一种明智的做法是通过 function。 当您拥有employee结构时,您可以执行以下操作:

void employee_init(struct employee* p)
{
    p->id      = 0;
    p->name[0] = '\0';
    p->salary  = 2000;
}

您还可以使用一个简单的宏:

#include <stdio.h>

typedef struct {
    int  id;
    char name[30];
    int  salary;
} Employee;

#define EMPLOYEE(var)   \
    Employee var;       \
    var.id      = 0;    \
    var.name[0] = '\0'; \
    var.salary  = 0;

int main()
{
    EMPLOYEE(john);
    printf("%d %s %d\n", john.id, john.name, john.salary);
    return 0;
}

或将两者结合起来:

#define EMPLOYEE(var) \
    Employee var;     \
    employee_init(&var);

当您使用malloc()时:

#define EMPLOYEE_DYN(var, n)  \
    Employee* var = malloc(sizeof(Employee) * n);  \
    employee_init(var);

从 C99 开始,您还可以执行以下操作:

#define EMPLOYEE(var) \
    Employee var = { .id = 0, .name = "", .salary = 0 }

更多类似构造函数的宏(在这种情况下需要#include <string.h> ):

#define EMPLOYEE(var, id_, name_, salary_) \
    Employee var;                          \
    var.id = id_;                          \
    strcpy(var.name, name_);               \
    var.salary = salary_;

或使用指定的初始化程序:

#define EMPLOYEE(var, id_, name_, salary_) \
    Employee var = { .id = id_, .name = name_, .salary = salary_ }

初步说明:您的结构的成员name是一个数组,而不是一个指针。 NULL不是它的有效值。 默认情况下初始化它的值是 all(30)-bytes-zero,这是完全不同的事情。

话虽如此,你得到默认初始化,嗯,默认为用 static storage duration 声明的对象 也就是说,所有在文件 scope 中声明的和在块 scope 中声明的所有内容,关键字static 对于这些情况,您不需要做任何特别的事情。

// at file scope
struct employee emp1;  // done

int do_something() {
    static struct employee emp2;  // done (but any changes persist across calls)
    // ...
    return 0;
}

对于那些具有自动存储持续时间的人——即不是 static 的块范围变量——您需要提供一个初始化程序。 理解这一点很重要

  • 尽管在聚合的初始化器周围需要大括号,但嵌套大括号对于嵌套聚合的初始化器是可选的;
  • 常量0可用于初始化任何标量,其结果与默认初始化将实现的结果相同;
  • 如果聚合的初始化程序没有初始化所有成员,那么那些未显式初始化的成员将被隐式默认初始化。

这一切意味着您可以通过初始化程序{0}实现与任何 object 的默认初始化等效的手动初始化(尽管此处要小心未指定长度的 arrays)。 特别是,这是完全惯用的:

int do_something_else() {
    struct employee emp3 = {0};

    // ...

    return 0;
}

请注意,初始化不是赋值。 该语法对于赋值语句不是(相当)有效的。

这就把我们带到了最后一种情况:已分配对象 这些不受默认初始化的影响,并且它们不能具有初始化器。 通过将它们设置为所有字节为零来设置它们的初始值是相当常见的,或者通过使用calloc()分配它们,或者通过在使用memset()分配后将它们填充为零。 然而,这些方法都不支持在所有情况下严格遵守程序,因为所有位为零的指针和浮点 object 表示不一定与从此类对象的默认初始化中获得的相同。

您总是可以单独为每个成员分配适当的值,但在现代 C 中,将分配的结构的值设置为默认初始化的最简单的方法是为其分配适当的复合文字值:

int do_a_third_thing() {
    struct employee *ep = malloc(sizeof(*ep));
    // ... check for / handle NULL ...

    *ep = (struct employee) {0}; // HERE

    // ...

    return 0;
}

在该示例中,表达式(struct employee) {0}具有struct employee类型和(初始)值,就好像它是使用{0}的初始化程序声明的一样。

当然,您可以做同样的事情来为任何结构或联合 object 分配一个新的、如同默认初始化的值,无论其存储持续时间如何。


综上所述,底线回答

我希望从该结构创建的所有员工(对象)的 ID = 0,名称 = NULL,工资 = 0。这可能吗?

不,这本身是不可能的。 C 没有默认或其他构造函数。 然而,正如我所展示的,如果默认初始化是用户想要的特定实例,那么他们很容易获得它。 如果这不是他们想要的,那么强迫他们这样做是没有用的。

这是另一种方式,使用“原型”方法。

# include <stdlib.h>
# include <string.h>
# include <stdio.h>

struct employee  {
    int id;
    char name [30];
    int salary;
};

struct employee const * const   create_employee_prototype()   {
    struct employee * prototype = (struct employee *) malloc( sizeof(struct employee) );
    prototype->id = 0;
    for (int i = 0; i < 30; ++i) { prototype->name[i] = 0; }
    prototype->salary = 0;
    return (struct employee const * const) prototype;
}

struct employee *   generate_new_employee_from_prototype( struct employee const * const prototype )   {
    struct employee * employee_out = malloc( sizeof( struct employee ) );
    employee_out = memcpy( employee_out, prototype, sizeof( struct employee ) );
    return employee_out;
}

int   main()   {
    struct employee const * const PROTOTYPE = create_employee_prototype();
    struct employee * employee1 = generate_new_employee_from_prototype( PROTOTYPE );
    printf( "Employee 1 initialised with id: %d, name: %s, and salary: %d.\n", employee1->id, employee1->name, employee1->salary );
    free( employee1 );
    free( (void *) PROTOTYPE );
}

在 memory 中有效地创建一个常量 object,您可以生成其副本。 缺点:以“不可见”方式在堆上生成,因此您需要知道/记住手动释放 memory。 (显然,您可以自由调整它以使用堆栈。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM