将数据分配给 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_BLOCKS
个 unsigned 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
选项。
我正在用 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_BLOCKS
个 unsigned 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
选项。