【问题标题】:Struct array typedef in struct shows incomplete datastruct 中的 struct 数组 typedef 显示不完整的数据
【发布时间】:2018-08-25 09:46:50
【问题描述】:

我遇到了一段代码,其中 typedef 数组是由结构创建的。然后在另一个结构中使用该 typedef。
在函数中接收 typedef 并使用其中的 typedef 初始化结构时,我只获取数组中第一个元素的数据。

下面我有一个简化的例子来说明我目前所得到的。

struct simple_struct {
    double a;
};

typedef struct simple_struct arr_typedef[2];

struct struct_with_typedef {
    const arr_typedef typedef_arr;
};

void foo(const arr_typedef arg_s) {
    struct struct_with_typedef test = {
        *arg_s
    };

    int i;
    for (i = 0; i < 2; i++) {
        printf("value: %f \n", test.typedef_arr[i].a);
    }
}

int main(int argc, char* argv[]) {
    arr_typedef d_test = { {1}, {2} };
    foo(d_test);

    return 1;
}

使用 gcc 4.4 编译并运行时,我看到以下输出:

~/public > ./test                  
value: 1.000000 
value: 0.000000

谁能解释为什么第二项的价值不可用?
如果我忽略了取消引用,我会在编译时得到以下错误,我也没有得到:

test.c:82:错误:使用类型“const struct simple_struct *”初始化类型“double”时类型不兼容


我已经删除了 typedef 并且相同的结果仍然存在。有点理解,确实给出了一个初始化器值。但是结构中只有一个成员,还是在后台展开?
如果是这样,您将如何初始化这两个值?

struct simple_struct {
    double a;
};

struct struct_with_arr {
    const struct simple_struct struct_arr[2];
};

void foo(const struct simple_struct arg_s[2]) {
    struct struct_with_arr test = {{*arg_s}};

    int i;
    for (i = 0; i < 2; i++) {
        printf("value: %f \n", test.struct_arr[i].a);
    }
}

int main(int argc, char* argv[]) {
    struct simple_struct d_test[2] = { {1}, {2} };
    foo(d_test);

    return 1;
}

【问题讨论】:

  • 当然你只得到第一个元素,这就是*arg_s 所做的。话虽如此,将数组隐藏在 typedef 后面是非常糟糕的做法,就像将指针隐藏在 typedef 后面一样糟糕。找不到这个bug的原因,其实是因为你把数组藏在了typedef后面。
  • 您只提供 1 个初始化值:*arg_s。如果你感到困惑,没关系!不要做这样的typedef!
  • 谢谢,我已经根据您的 cmets 更新了问题,提供了更多信息
  • *X 表示X[0]

标签: c struct typedef initializer


【解决方案1】:

在此声明中

struct struct_with_typedef test = {
    *arg_s
};

使用struct simple_struct 类型的对象来初始化const arr_typedef 类型的数组。

首先,您需要将初始化程序括在大括号中,并为数组的第二个元素添加初始化程序。

初始化数组的正确方法如下

#include <stdio.h>

struct simple_struct 
{
    double a;
};

typedef struct simple_struct arr_typedef[2];

struct struct_with_typedef 
{
    const arr_typedef typedef_arr;
};

void foo( const arr_typedef arg_s ) 
{
    struct struct_with_typedef test = 
    {
        { arg_s[0], arg_s[1] }
    };

    for ( int i = 0; i < 2; i++ ) 
    {
        printf("value: %f \n", test.typedef_arr[i].a);
    }
}

int main( void ) 
{
    arr_typedef d_test = { {1}, {2} };
    foo(d_test);

    return 0;
}

程序输出是

value: 1.000000 
value: 2.000000 

您也可以通过以下方式编写初始化程序

struct struct_with_typedef test = 
{
    { *arg_s, *( arg_s + 1 ) }
};

考虑到用作初始化表达式的数组指示符被隐式转换为指向其第一个元素的指针。取消引用指针,您将获得第一个元素本身。

【讨论】:

  • 谢谢!现在我明白了
【解决方案2】:

C 中没有语法可以用一个初始化器来初始化一个数组,该初始化器代表另一个数组以从中复制值。

要修复您的代码,您可以执行以下选项之一:

  1. 列出成员:struct struct_with_arr test = {{arg_s[0], arg_s[1]}};
  2. 改变函数接受struct struct_with_arr作为参数类型,在这种情况下你可以使用struct struct_with_arr test = arg;
  3. 不带初始化程序的复制:struct struct_with_arr test; memcpy(&amp;test.struct_arr, arg_s, sizeof test.struct_arr);。 (实际上你不能使用这个选项,因为你已经将结构元素定义为const ...在我看来,这首先不是一个好主意)

为了完整起见,我将提及代码:

struct struct_with_arr foo = *(struct struct_with_arr *)arg_s;

这是技术上未定义的行为之一(如果参数源实际上不是struct_with_arr),但可能适用于任何存在的实际编译器。我的建议是不要这样做。

【讨论】:

  • 感谢您的回答!遗憾的是,我们无法更改 const 或函数原型的任何内容,因为这些超出了我们的控制范围。所以扩展它们是要走的路
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多