将数据分配给char数组

时间:2020-10-27 18:59:40

标签: arrays c pointers struct dereference

我正在用C进行代码编写有关块存储的分配(对于OS类)。我的结构(在另一个文件中typedef为block_store_t)是

struct block_store{
    unsigned char data[BLOCK_SIZE_BYTES][BLOCK_STORE_NUM_BLOCKS];
    //block_size_bytes is 32, block_store_num_blocks is 512
};

我将所有数据放入char数组中,因为char是一个字节长。为了跟踪正在使用的块,我们使用了位图,必须将其存储在块存储数据数组的块127中。因此,访问它应该类似于

bs->data[127]

或类似的东西。我在其中声明初始化块存储结构的代码如下:

block_store_t *block_store_create()
{
    bitmap_t *bm = bitmap_create(BITMAP_SIZE_BITS);

    block_store_t *bs = malloc(sizeof(block_store_t));
    if (bs == NULL) return NULL;

    for (int i = 0; i < (BITMAP_SIZE_BLOCKS); i++)
    {
        bitmap_set(bm, i + BITMAP_START_BLOCK);
    }

    //I've tried the ways two ways below, both give seg faults
    //bs->data[BITMAP_START_BLOCK] = (unsigned char*)*bm;
    //memcpy(bs.data[BITMAP_START_BLOCK], bm, BITMAP_SIZE_BYTES);
    return bs;
}

由于位图的类型为bitmap_t,如何获取位图位于数据数组的块127中,又如何再次访问它?如果位图大于一个块的大小(在我的情况下,位图将是两个块的大小,因为每个块512位/ 8/32字节)怎么办?

tl; dr如何将不是char的数据分配给结构内部的char数组?我正在使用char,因为它长一字节。

2 个答案:

答案 0 :(得分:1)

如何将不是char的数据分配给结构内部的char数组?我正在使用char,因为它长一字节。

您不能分配(这意味着使用=运算符)将结构类型的对象更改为类型unsigned char的对象。如果您的bitmap_t是数字类型,则可以进行这种分配,但是除非它是字符类型,否则结果将丢失数据。您根本无法分配整个数组(与分配给非数组类型的数组元素相反)。

但是,您可以将对象表示形式的字节复制到字符数组中。为此,您的memcpy()方法基本上是正确的:

    //memcpy(bs.data[BITMAP_START_BLOCK], bm, BITMAP_SIZE_BYTES);

尤其要注意,bs.data[BITMAP_START_BLOCK]指定的值是unsigned char的数组,因此,它会自动转换为指向该数组第一个元素的指针,该指针将位于与BITMAP_START_BLOCK * BLOCK_STORE_NUM_BLOCKS的开头相距bs.data个字节的偏移量。

但是该偏移量表达式使我认为您对block_store结构的定义与您打算的有所不同。这个...

    unsigned char data[BLOCK_SIZE_BYTES][BLOCK_STORE_NUM_BLOCKS];

...将data声明为BLOCK_SIZE_BYTES元素的数组,每个元素都是类型为BLOCK_STORE_NUM_BLOCKS的{​​{1}}元素的数组。我认为您已经颠倒了尺寸。与宏名称一致的声明为:

unsigned char

unsigned char data[BLOCK_STORE_NUM_BLOCKS][BLOCK_SIZE_BYTES]; 的字节大小是相同的,但是data的含义彼此不同。使用后一种声明bs.data[BITMAP_START_BLOCK],您在data中产生的偏移量将是memcpy开头的BITMAP_START_BLOCK * BLOCK_SIZE_BYTES个字节,我认为这是您想要的。

我将如何再次访问它?

如果您打算仅依靠语言标准定义的行为,则可以将位图复制回data类型的对象:

bitmap_t

但是请注意,所涉及的副本是 shallow 。如果要复制的对象包含指针,那么将要复制的是指针,而不是它们指向的数据。

不符合要求的替代方法

C的所谓“严格别名规则”禁止访问您的bitmap_t bm2; memcpy(&bm2, bs.data[BITMAP_START_BLOCK], BITMAP_SIZE_BYTES); 或其struct block_store成员,就好像其中一部分是data。但是,从历史上看,这种访问是相对普遍的做法。这将采用强制转换块或字节指针的形式,以键入bitmap_t并取消引用结果。例如:

bitmap_t *

这种方法的优点是表达式更简单,复制更少,但是您的编译器可以使用此类代码自由地执行许多令人惊讶的事情。在走那条路线之前,请确保您知道如何防止编译器在这方面感到惊讶。例如,对于GCC,您需要为编译器指定// requires a definition of bitmap_t in scope: (bitmap_t *) bs.data[BITMAP_START_BLOCK] = *bm; bitmap_set((bitmap_t *) bs.data[BITMAP_START_BLOCK], x); 选项。

答案 1 :(得分:0)

取决于os。
您需要在此处处理对齐方式,而这没有任何标准。
对于gcc和msvc就像这样

#include <stdio.h>
#include <stddef.h>

int main(int argc , char *argv[])
{
    struct blockheader {
#pragma pack(1)
        unsigned char hashPrevBlock[30];
        unsigned short b;  //2 bytes
        unsigned char merk[72];
    };

    unsigned char c[104] = {0};
    struct blockheader *a = (struct blockheader *)c;
    a->b = 400 ;
    printf("and then %d  ,   %d\n" ,a->b ,offsetof(struct blockheader, b));
}

对于阵列的批量加载部分,您可以使用offsetof来确定大小和起点。

gcc本机样式是

    struct blockheader_on_gcc {
        unsigned char hashPrevBlock[30];
        unsigned short b;  //2 bytes
        unsigned char merk[72];
    }__attribute__((aligned(1)));

如果在末尾有多余的字节是np。
如果有问题,可以使用__attribute__((packed))