使用第一个成员类型的指针调用malloc是否有效?

时间:2016-05-16 10:08:36

标签: c struct

我正在构建一个哈希库,这个库适用于不同的struct,所有struct都有unsigned类型作为第一个成员,例如:

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

struct data {
    unsigned hash;
    void (*func)(struct data *);
};

struct another_data {unsigned hash; int value;};

static void *hash_insert(const char *text, size_t size)
{
    unsigned *hash;

    hash = malloc(size);
    // *hash = hash(text);
    *hash = (unsigned)strlen(text);
    return hash;
}

static void func(struct data *data)
{
    printf("%u\n", data->hash);
}

int main(void)
{
    struct data *data;

    data = hash_insert("Some text", sizeof *data);
    data->func = func;
    data->func(data);
    free(data);
    return 0;
}

由于struct的第一个成员和struct本身具有相同的对齐要求,因此使用第一个成员类型的指针调用malloc是否有效为整个struct预留空间?

unsigned *hash = malloc(size); /* where size is the size of the struct */

修改

在@MohitJain提供的related question中:

struct Msg
{
   unsigned int a;
   unsigned int b;
};

...

uint32_t* buff = malloc(sizeof(Msg));

// Alias that buffer through message
Msg* msg = (Msg*)(buff);
  

严格别名规则使此设置非法

但在我的情况下,我从函数返回void *,我可以在main内使用此(返回)指针而没有对齐问题,这个假设是否正确?

5 个答案:

答案 0 :(得分:2)

malloc保证返回任何类型的内存。

因此,无论不同子类型的对齐要求如何,它都能正常工作。

答案 1 :(得分:2)

关于有效类型和指针别名的规则说,在结构(或任何其他“聚合”)和与结构中第一个出现的成员相同类型的指针之间转换指针是很好的。另一条规则说结构一开始就不允许填充。

因此,就C标准而言,这是好的......这并没有真正说明程序的质量。

代码没有多大意义。你显然想要使用整个结构,那么为什么不返回结构类型的指针呢?不要为了它而使事情复杂化。在不需要时,应始终避免使用void*,以提高类型安全性。

总的来说,所有这些事情都会在具有适当程序设计的多文件项目中解决。如果你有一个带有散列类型的单独文件和使用该类型的所有函数,那么毫无疑问如何编写程序。

答案 2 :(得分:1)

由于结构成员按照声明的顺序分配,使用

unsigned *hash = malloc(size); /* where size is the size of the struct */
如果你的pourpose只是使用哈希数据,

可以工作。 如果你想在它上面应用指针aritmetic它会失败,所以在这种情况下使用

hash++

是一种未定义的行为。

答案 3 :(得分:1)

是的,第一个成员类型指向malloc返回的内存(内存对齐任何数据类型)是完全正常的。如果您不小心,以后可能会导致问题。

[Joachim Pileborg的答案@ Maintaining an array of pointers in C that points to two related types摘录并略有修改]

在其他结构中具有结构或在其他结构中具有公共数据类型是在C中模拟继承的常用方法。此公共成员应包含“继承”层次结构中所有结构共有的最小数据集,并且必须始终是继承结构中的第一个成员。

此计划的可能问题是:

这种“继承”方案适用于所有类似现代PC的系统及其编译器,并且已经很长时间了,但并不能保证它可以在所有系统和所有编译器上运行(如果您正在计划中)将代码移植到一些罕见的系统,你可能需要注意奇怪的硬件和编译器,但“继承”方案不起作用的情况非常少,大多数人永远不会接触到这样的系统。整个生命周期。)但是一旦你用struct data *指向相同的内存,你可能会落入严格别名规则的维持时间。所以你需要小心。进一步阅读What is the strict aliasing rule?

答案 4 :(得分:-1)

unsigned *hash = malloc(size);

这将创建分配无符号整数数组。分配的整数总数为size/sizeof(int)hash这里是指向int。

的指针
  

由于struct的第一个成员和struct本身具有相同的对齐要求,使用第一个成员类型的指针调用malloc是否有效,以便为整个struct保留空间?

关键是,hash这里是一个单独的变量,它与结构中的hash无关。 (它在一个单独的命名空间中,如果你想查找它)

可以然后将hash转换为struct变量。

struct data *data;
unsigned *hash = malloc(size * sizeof(struct));
data = (struct data *) hash;

但是,重点是什么。您也可以删除不必要的unsigned hash指针,并使用传统的。

struct data *data;
data = malloc(size * sizeof(struct));