在C中写入和读取不同类型的内存

时间:2016-12-26 18:06:59

标签: c pointers

- 理论

我有一组具有不同类型的变量S,并且我有一个指向内存地址的指针P,其大小为S.现在,我想将S的所有值分配给P然后再读回来。

这背后的重点是手动构建类似于结构的东西。

- 我做了什么:

让我们说我们有int i,char c和char * s作为我们的S

uint8_t* foo(int i, char c, char* s) {
    uint8_t* r = malloc(sizeof(i) + sizeof(c) + sizeof(s));
    *r = i;
    *(r+sizeof(i)) = c;
    *(r+sizeof(i)+sizeof(c)) = s;
    return r;
}

int main(void) {
    uint8_t * a = foo(500, 'a', "hello");
    printf("%d, %c, %s\n", *a, *(a+sizeof(int)), (a+sizeof(int)+sizeof(char)) );
    return 0;
}

这里的问题是我只将数据分配给第一个字节,然后只读取第一个字节。

- 问题:

如何告诉编译器foo on * r = i;将i分配给* r的下4个字节,然后将主读取* a分配为4个字节,然后对c和s执行相同的操作?

2 个答案:

答案 0 :(得分:2)

我希望尽可能让计算机做数学计算。在这种情况下,我会使用struct

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

struct multi_type {
    int i;
    char c;
    char *s;
};

struct multi_type *foo(int i, char c, char *s) {
    struct multi_type *result = malloc(sizeof(*result));
    if (result == NULL) {
        return NULL;
    }
    result->i = i;
    result->c = c;
    result->s = s;
    return result;
}

int main(void) {
    struct multi_type *a = foo(500, 'a', "hello");
    if (a) {
        printf("%d, %c, %s\n", a->i, a->c, a->s);
        free(a);
    }
    return 0;
}

<强>输出

500, a, hello

此代码也更易于维护。如果struct multi_type中的某个类型发生更改或我需要添加类型,则需要更改的代码更少。

答案 1 :(得分:1)

你必须施放你的左值,以便它们具有正确的类型:

uint8_t *foo(int i, char c, char *s) {
    uint8_t *r = malloc(sizeof i + sizeof c + sizeof s);
    *(int *)r = i;
    *(char *)(r + sizeof i) = c;
    *(char **)(r + sizeof i + sizeof c) = s;
    return r;
}

为了阅读它们,还需要转换为适当的类型:

int main(void) {
    uint8_t *a = foo(500, 'a', "hello");
    printf("%d, %c, %s\n", *(int *)a, *(char *)(a + sizeof(int)), *(char **)(a + sizeof(int) + sizeof(char)));
    return 0;
}

正如@chux在评论中指出的那样,这确实是未定义的行为。与以前一样,可以使用C11 _Alignof运算符来获得符合标准的代码:

// Get the smallest multiple of _Alignof(type) >= off
#define GET_ALIGNED_OFFSET(off, type) ((off + _Alignof(type) - 1) / _Alignof(type) * _Alignof(type))

uint8_t *foo(int i, char c, char *s) {
    size_t offset1 = GET_ALIGNED_OFFSET(sizeof i, char);
    size_t offset2 = GET_ALIGNED_OFFSET(offset1 + sizeof c, char *);
    uint8_t *r = malloc(offset2 + sizeof s);
    *(int *)r = i;
    *(char *)(r + offset1) = c;
    *(char **)(r + offset2) = s;
    return r;
}

虽然当然@David Cullen的答案仍然是从工程角度来看的最佳解决方案。