0

I am coding in C doing an assignment regarding block storage (for an OS class). My struct (which is typedef to block_store_t in another file) is

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

I am putting all the data into a char array because chars are one byte long. To keep track of which blocks are in use, we use a bitmap which we have to store at block 127 of the block store data array. So, accessing it should be something like

bs->data[127]

or something similar to that. My code where I declare an initialize the block storage struct is like so:

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;
}

Since the bitmap is of the type bitmap_t, how do I get the bitmap to be in block 127 of the data array, and how would I access it again? What if the bitmap is larger than the size of one block (in my case, the bitmap will be the size of two blocks, because 512 bits / 8 / 32 bytes per block)?

tl;dr 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.

4
  • 1
    We need a working / failing example that we can compile. How do we know what bitmap_create does, what it returns or how it fails? How do we know what bitmap_set does? How do we know that BITMAP_SIZE_BLOCKS is longer than 144 (data + bitmap)? how do we know what bitmap_t even is? Commented Oct 27, 2020 at 19:05
  • bitmap_create was a given function, as was bitmap_set. I don't feel comfortable sharing those because my professor wrote them. BITMAP_SIZE_BLOCKS is a constant that would be 2 with the numbers we were given. bitmap_t is just a struct he created. The more basic question is I have a data struct that is 2 blocks long, how do I assign it to this array? Commented Oct 27, 2020 at 19:11
  • 1
    Well, we can't help you if we're blind. If bitmap_create allocates memory, you probably can't put the returned bitmap within the block_store_t... you might want to create the bitmap some other way. Also, are you sue bitmap_create takes the bitmap size rather than the BITMAP_START_BLOCK length? or maybe your for loop should be BITMAP_SIZE_BITS long instead? Are they the same value? And why i + BITMAP_START_BLOCK? Commented Oct 27, 2020 at 19:32
  • Well darn, bitmap_create does allocate memory. I wonder what my professor wants us to do in that case, since we have to store that bitmap at block 127, but use his functions for the bitmap. Commented Oct 27, 2020 at 19:36

2 Answers 2

1

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.

You cannot assign (which implies using the = operator) an object of structure type to an object of type unsigned char. If your bitmap_t were a numeric type then such an assignment would be allowed, but unless it was a character type, the result would be subject to losing data. You cannot assign to whole arrays at all (as opposed to assigning to array elements of non-array type).

You can, however, copy the bytes of an object's representation into a character array. To that end, your memcpy() approach is substantially right:

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

Note in particular that the value designated by bs.data[BITMAP_START_BLOCK] is an array (of unsigned char), and as such it is automatically converted to a pointer to the first element of that array, which will be at an offset of BITMAP_START_BLOCK * BLOCK_STORE_NUM_BLOCKS bytes from the beginning of bs.data.

But that expression for the offset makes me think that you have defined your block_store structure differently than you meant to do. This ...

    unsigned char data[BLOCK_SIZE_BYTES][BLOCK_STORE_NUM_BLOCKS];

... declares data as an array of BLOCK_SIZE_BYTES elements, each of them an array of BLOCK_STORE_NUM_BLOCKS elements of type unsigned char. I think you've reversed the dimensions. The declaration that would be consistent with the macro names would be:

    unsigned char data[BLOCK_STORE_NUM_BLOCKS][BLOCK_SIZE_BYTES];

The size in bytes of the data is the same either way, but the meaning of bs.data[BITMAP_START_BLOCK] differs from one to the other. With the latter declaration of data, the resulting offset in your memcpy would be BITMAP_START_BLOCK * BLOCK_SIZE_BYTES bytes from the start of the data, which I think is what you want.

how would I access it again?

If you intend to rely only on behavior defined by the language standard, then you would copy the bitmap back to an object of type bitmap_t:

bitmap_t bm2;
memcpy(&bm2, bs.data[BITMAP_START_BLOCK], BITMAP_SIZE_BYTES);

Be well aware, however, that the copies involved are shallow. If the objects being copied contain pointers, then it is the pointers that will be copied, not the data to which they point.

Non-conforming alternative

C's so-called "strict aliasing rule" forbids accessing your struct block_store, or its data member, as if part of it were a bitmap_t. Nevertheless, such accesses have historically been relatively common practice. That would take the form of casting block or byte pointers to type bitmap_t * and dereferencing the result. For example:

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

The perceived advantages of that approach are simpler expressions and less copying, but your compiler is free to do any number of surprising things with such code. Before going that route, be sure you know how to prevent the compiler from surprising you in that regard. For example, with GCC, you would need to specify the -fno-strict-aliasing option to the compiler.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your answer! memcpy(&(bs->data[BITMAP_START_BLOCK]), bm, BITMAP_SIZE_BYTES); segfaults, as does memcpy(bs->data[BITMAP_START_BLOCK], bm, BITMAP_SIZE_BYTES); , do you know why that is? How do I copy memory correctly here?
@esb5415, if that segfaults, it is most likely for one of these reasons: (1) the index-order swap I talked about in this answer; OR (2) bs is not a valid pointer to a struct block_struct; OR bm` is not a valid pointer to an object of size at least BITMAP_SIZE_BYTES.
Note also that although it is not harmful, it also serves no particular semantic purpose to introduce the & operator in that line as you have done. The expression bs->data[BITMAP_START_BLOCK] has array type, so it is automatically converted to an appropriate pointer.
Alternatively, if you have already performed the index-order swap, then perhaps (4) BITMAP_START_BLOCK is greater than BLOCK_STORE_NUM_BLOCKS - number_of_blocks_occupied_by_a_bitmap.
0

it depends of os .
you'll need to deal with alignment here and there's no standard on that.
for gcc and msvc it will be like that

#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));
}

for bulk load part of the array you then can use offsetof for sizes and startpoints.

gcc native style on that is

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

if it's np to have extra bytes at the end.
if it's a problem there's __attribute__((packed))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.