【问题标题】:Initializing a C struct array, with a size not known at compile time初始化一个 C 结构数组,其大小在编译时未知
【发布时间】:2012-12-15 14:50:52
【问题描述】:

我没有找到这个问题的确切答案,所以要么这是一个愚蠢的问题,要么是显而易见的。我想知道它是否会产生未定义的行为。

我定义了一些结构类型:

typedef struct {
    char string1[17];
    char string2[33];
    int   someInt;
    float someFloat;
} my_struct_t;

我需要该结构的多个实例(就像您在结构数组中一样),但对象的数量在编译时是未知的。

这样初始化对吗?

my_struct_t *myStruct;
size_t noOfElements;
size_t completeSize;
int index;    

/* ...code which sets the number of elements at runtime... */

completeSize = sizeof(my_struct_t) * noOfElements;

myStruct = malloc(completeSize);
memset(myStruct, 0, completeSize);

/* ...and then access it as if it were an array...*/

myStruct[index].someInt = 10; // index < noOfElements

这样做安全吗? memset() 部分是我担心的。

【问题讨论】:

    标签: c pointers struct initialization memset


    【解决方案1】:

    使用malloc 后跟memset 是可以的,但您可能希望考虑使用(未充分使用的)calloc。例如:

    pMyStruct = calloc(noOfElements, sizeof(my_struct_t));
    

    这将为所需数量的元素分配内存,将它们初始化为二进制零。

    【讨论】:

    • 我愿意,但我正在使用的平台仅支持标准 C 库的一个子集。 calloc() 不幸的是不可用。
    • @Tomislav:奇怪,它应该在 stdlib.h 中。无论如何,看起来你被 malloc 和 memset 困住了。
    • 这很奇怪。比这更奇怪的是,我什至不允许包含任何 ANSI C 头文件。事实上,我什至不能调用 malloc()。相反,我调用一个具有不同名称的函数,文档声明它充当标准 C malloc()。去搞清楚。因此,我正在编写的代码的可移植性并不是我的第一要务。 :)
    【解决方案2】:

    这样做安全吗? memset() 部分是我担心的。

    是的,这是安全的,因为这不会导致任何未定义的行为(缓冲区溢出、未初始化的值等)。

    但是,它不一定会将您的值设置为零。 memsetbits 设置为 0,但这不一定与设置相同,例如float0 的值(尽管在实践中,在大多数普通平台上都可以)。

    【讨论】:

    • 谢谢。所以分配给指针的整个内存将被清零,不会有溢出。这已经足够好了,但也感谢有关整数类型值的警告。
    【解决方案3】:

    这样做安全吗? memset() 部分是我担心的。

    您担心是对的 - 您的 memset 只是将所有位设置为零,这并不一定将成员设置为 0。

    例如,没有什么可以保证 all-bits-0 实际上对于浮点数表示 0。指针也是如此:使其全位为 0 并不意味着它一定是 NULL


    编辑

    NULL 可能表示为全位 0,也可能不表示为全位 0。引用 C 常见问题解答:

    空指针的内部(或运行时)表示,它可以 或者可能不是 all-bits-0 并且可能因不同而不同 指针类型。

    【讨论】:

    • 没有任何保证,但 C 委员会也这样说:“据委员会所知,​​所有机器都将所有位为零视为浮点零的表示。”
    • @ouah 很高兴知道 :-) 最好在安全方面犯错
    • 具有所有0 位的指针始终是空指针,它们与NULL 宏比较相等,尽管它们不能具有相同类型的NULL。实际上,0 是一个空指针常量
    • @effeffe 不这么认为。你能提供报价吗? c-faq.com/null/machexamp.html
    • @effeffe 我要说的是,将指针设置为 0 并不会在所有平台上使其为 NULL。
    【解决方案4】:

    您代码中的memset 会将所有位设置为0,这可能是您想要做的,也可能不是。特别是,不能保证全为零的指针是空指针。全零位的浮点值也不为零。

    如果您希望您的代码完全可移植,那么您应该初始化每个元素。

    my_struct_t *arr = malloc(N * sizeof arr[0]);
    const my_struct_t default_my_struct = { 0 };
    for (int i=0; i<N; i++)
        arr[i] = default_my_struct;
    

    或者您可以使用 C99 复合文字进行初始化:

    my_struct_t *arr = malloc(N * sizeof arr[0]);
    for (int i=0; i<N; i++)
        arr[i] = (my_struct_t) { 0 };
    

    在实践中,您必须努力找到一个 C 实现,上面的代码将与使用 memset 的变体产生不同的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-30
      • 2013-10-20
      相关资源
      最近更新 更多