【问题标题】:Initialize array of 3-value structures using memset使用 memset 初始化 3 值结构数组
【发布时间】:2015-06-05 21:13:51
【问题描述】:

如何用值初始化结构数组? 所以,我有 rgb 值的结构颜色。

struct color{
    GLfloat r;
    GLfloat g;
    GLfloat b;
}

并尝试使用 1.0f 对其进行初始化。

color* cArray = (color*) malloc(w*h*sizeof(color));
memset(&cArray, 1.0, sizeof color);

但是我在 cArray[0] 上得到分段错误,而不是正确的工作。 我想念什么?

【问题讨论】:

  • memset 用于将所有值设置为0-1。使用循环将数组的所有值设置为 0-1 以外的任何值。
  • 请注意,color 不能在 C(即 C++)中这样使用。 struct 有自己的命名空间,所以你必须要么 typedef 结构体要么在指针的定义中使用 struct color

标签: c arrays opengl memory memset


【解决方案1】:

注意:不要将void *malloc() 的结果)转换为其他指针,始终检查malloc()& 朋友的结果

Memset 采用无符号字符(很可能是 8 位)并将传递的区域视为字符数组。它不知道结构、数组等。只是一个 char 的一维数组。 (正如@chqrlie 所指出的,memset() 实际上需要一个int;但是,它在内部转换为unsigned char)。

段错误是因为您传递了cArray 的地址,它是指向实际数组的指针,而不是数组本身的值。

对于浮点数,memset() 很可能只有将其设置为 all-0 才有意义:

memset(cArray, 0, sizeof(struct color) * w * h);

注意:memset 不知道数据类型。它只需要一个指向内存块的指针和一个计数并将值存储到该区域。 负责所有论点均有效!

请注意,使用0 写入内存区域实际上是浮点零(0.0,实际上是+0.0),因为这会清除所有位。这是为浮点数设计编码的人的一个绝妙意图。

正如您之前分配的那样,您可以使用calloc() 组合它。这将分配并清除数组的内存区域。但是,如果您打算明确设置所有值,则最好坚持使用malloc()

如果要设置其他浮点值,则必须编写自己的循环。但是,您可以将数组视为一维数组。

for ( size_t i = 0 ; i < w * h ; i++ )
    cArray[i] = (struct color){ .r = 1.0, .g = 1.0, .b = 1.0 };

使用复合文字。或者,您也可以单独设置字段。

如果您想提高速度,那么复合字面量方法可能是最快的。这样,编译器可以很好地将所有值加载到三个寄存器中,并使用 store-multiple 将它们直接存储到内存中。不管它可能会做什么,我敢打赌编译器会识别该模式并进行优化,因为它通常用于非常大的循环。

【讨论】:

  • 哇,这些移动的投票 div 很有趣,而且它们不会为自己的帖子移动!
  • @iharob:如果我能理解你的意思,我可能也会“哇”。
  • @chqrlie:不,我没有(吹口哨:-)
  • 答题分数随着答题正文移动,之前不是。
  • 好的,我的键盘有问题。这些字母并不总是我期望它们出现的地方。幸运的是,我的编译器有所有警告:-)
【解决方案2】:

您不能使用memset() 设置float 值。

memset()函数用于字节,所以不能用于floats,需要显式初始化每个成员

这是memset()的签名

void *memset(void *s, int c, size_t n);

虽然它期望 int1 作为它的第二个参数,但标准说

7.24.6 杂项函数

7.24.6.1 memset 函数

  1. memset 函数将c 的值(转换为unsigned char 复制到指向对象的第一个n 字符 中发给s

转换为unsigned char”所以它设置字节。

还要考虑以下几点:

  1. don't need to cast the return value of malloc(),你不做就好了。

  2. 始终检查malloc() 是否返回非NULL,特别是在分配大量内存时。


1如你所见,你不能通过浮点数。

【讨论】:

  • 好的,我会注意的。那么我可以用什么来设置这个数组呢?我在顶点数组中有超过 50000 个顶点,所以 for 循环对于每帧更新来说太昂贵了
  • memset() 毕竟会循环,所以我认为不会有其他方法。
  • @mersinvald:for 循环可以被编译器优化到最大。请参阅此页面:gcc.godbolt.org/#。您还可以保留预初始化数组的副本并使用memcpy 来初始化数组。
  • @chqrlie 是的,就像@Olaf 的答案中的那个。
  • 有趣的是有人会否决这个答案,我希望他们发表评论,因为我真的看不出它有什么问题,但最近似乎有人只是在投反对票 my 帖子,这是一件愚蠢的事情。由于连续投票,我有超过 100 个代表点被逆转。
【解决方案3】:

您的代码存在多个问题:

您分配w x h 的矩阵color 结构:

color *cArray = (color*) malloc(w * h * sizeof(color));

强制转换在 C 中不是必需的,但对于推荐的替代方案意见不一。更安全的版本是:

color *cArray = malloc(w * h * sizeof(*cArray));

更重要的是,我们对memset 的调用在多个方面都不正确:

memset(&cArray, 1.0, sizeof color);
  1. 您传递的是指针的地址,而不是指针 cArray 的值。
  2. 您只能传递单个color 结构的大小。这个大小超过了指针的大小,因此崩溃。如果您打算设置整个数组,您应该将大小存储到一个临时变量中。
  3. 您传递 double 而不是 int 作为要设置的值。您不能用memset 初始化double 值的数组:此函数通过将所有字节设置为相同的值来初始化内存块。如果您的系统使用 IEEE-754 表示浮点值,则传递 0 将正确初始化 double 值,否则它可能会调用未定义的行为。

你必须用循环初始化矩阵:

for (size_t i = 0, n = w * h; i < n; i++) {
    cArray[i].r = cArray[i].g = cArray[i].b = 1.0;
}

现代编译器可以优化这个循环。我建议你玩这个非常有趣的工具:http://gcc.godbolt.org/#

您还可以保留一个预初始化数组的副本,并使用memcpy 来初始化分配的数组。

【讨论】:

    【解决方案4】:

    首先,颜色(在您的情况下)是 3 个字节,而不是 3 个浮点数。

    然后这段代码:

    struct color{
        GLfloat r;
        GLfloat g;
        GLfloat b;
    }
    
    and trying to initialize it with 1.0f.
    
    color* cArray = (color*) malloc(w*h*sizeof(color));
    memset(&cArray, 1.0, sizeof color);
    

    会导致编译器发出几个警告:

    由于编译器不知道“颜色”是什么原因:

    syntax errors in the struct definition
    and references to the struct are missing the 'struct' modifier.
    

    在调用 malloc()(和函数族)时,始终检查 (!=NULL) 返回值以确保操作成功。

    在 C 中,不要从 malloc() (和函数族)中转换返回值

    注意结构定义以';'结尾

    建议使用:

    struct color
    {
        char r;
        char g;
        char b;
    };
    
    struct color* cArray = NULL;
    if( NULL == (cArray =malloc(w*h*sizeof(struct color))))
    { // then malloc failed
        perror( "malloc for struct color array failed" );
        exit( EXIT_FAILURE )
    }
    
    // implied else, malloc successful
    
    memset(&cArray, 1, w*h*(sizeof (struct color) );
    

    【讨论】:

    • OpenGL wiki 声明 different。您从哪里得到 GLfloat 是一个字节的想法?
    • 确实 GLfloat 似乎是一个 32 位 IEEE-754 浮点值又名 float
    猜你喜欢
    • 2011-03-24
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多