将数据分配给 char 数组

Assign data to char array

我正在用 C 语言编写有关块存储的作业(对于 OS class)。我的结构(在另一个文件中是 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
};

我将所有数据放入一个字符数组中,因为字符是一个字节长。为了跟踪正在使用的块,我们使用了一个位图,我们必须将其存储在块存储数据数组的块 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,因为它只有一个字节长。

这取决于 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))

How do I assign data that is not a char to a char array that is inside of a struct? I'm using char because it is one byte long.

您不能将结构类型的对象分配(这意味着使用 = 运算符)到类型 unsigned char 的对象。如果您的 bitmap_t 是数字类型,则允许这样的赋值,但除非它是字符类型,否则结果可能会丢失数据。您根本不能分配给整个数组(与分配给 non-array 类型的数组元素相反)。

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

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

特别注意 bs.data[BITMAP_START_BLOCK] 指定的值是一个数组(unsigned char),因此它会自动转换为指向该数组第一个元素的指针,它将从 bs.data.

的开头偏移 BITMAP_START_BLOCK * BLOCK_STORE_NUM_BLOCKS 字节

但是偏移量的表达式让我认为您对 block_store 结构的定义与您预期的不同。这个...

    unsigned char data[BLOCK_SIZE_BYTES][BLOCK_STORE_NUM_BLOCKS];

... 将 data 声明为 BLOCK_SIZE_BYTES 个元素的数组,每个元素都是 BLOCK_STORE_NUM_BLOCKSunsigned char 类型元素的数组。我认为你已经颠倒了维度。与宏名称一致的声明为:

    unsigned char data[BLOCK_STORE_NUM_BLOCKS][BLOCK_SIZE_BYTES];

data 的大小(以字节为单位)是相同的,但 bs.data[BITMAP_START_BLOCK] 的含义各不相同。使用 data 的后一个声明,您的 memcpy 中的结果偏移量将从 data 的开头开始 BITMAP_START_BLOCK * BLOCK_SIZE_BYTES 个字节,我认为这就是您想要的。

how would I access it again?

如果您打算只依赖语言标准定义的行为,那么您可以将位图复制回 bitmap_t:

类型的对象
bitmap_t bm2;
memcpy(&bm2, bs.data[BITMAP_START_BLOCK], BITMAP_SIZE_BYTES);

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

Non-conforming备选方案

C 的 so-called“严格别名规则”禁止访问您的 struct block_store 或其 data 成员,就好像它的一部分是 bitmap_t 一样。然而,这种访问在历史上一直是相对普遍的做法。这将采用将块或字节指针转换为类型 bitmap_t * 并取消引用结果的形式。例如:

// 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);

这种方法的明显优势是更简单的表达式和更少的复制,但您的编译器可以自由地使用此类代码做任何令人惊讶的事情。在走那条路之前,请确保您知道如何防止编译器在这方面让您感到惊讶。例如,对于 GCC,您需要为编译器指定 -fno-strict-aliasing 选项。