'Is it possible to set bits of a void* value without type casting it to an int or char?

I am working on a project that requires me to allocate some space using the mmap function and I need to create a bitmap in the beginning of the allocated space. The bitmap shows which sections are occupied and which sections are free, sections being divided into 8 byte words. Each bit in the bitmap indicates whether its corresponding word is free or occupied. I am pointing to the space via a void* but I can not individually set the bits without making a type cast into an int. I know that I can set the bits in bulks of 32 by setting each int to -1, since my compiler uses 2's compliment but different compilers have different implementations. It also has the problem of using unnecessary bits if the number of words is not a multiple of 32.

Is it possible to set those bits one by one without type casting them?



Solution 1:[1]

Is it possible to set those bits one by one without type casting them?

Yes.

Let us take advantage of:

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. C17dr ยง 6.2.5 28

Given void * and some bit index:

// No cast, access void * via union.
void set_bit_without_cast1(void *data, size_t bit_index) {
  union {
    void *vp;
    unsigned char *ucp;
  } u = { .vp = data };
  u.ucp[bit_index / CHAR_BIT] |= 1u << (bit_index % CHAR_BIT);
}

Or by simple assignment, no cast needed from void * to object pointer.

// No cast needed.
void set_bit_without_cast2(void *data, size_t bit_index) {
  unsigned char *ucp = data;
  ucp[bit_index / CHAR_BIT] |= 1u << (bit_index % CHAR_BIT);
}

OP has "I am pointing to the space via a void*". Consider instead alternative code such so that "... pointing to the space via a unsigned char *" to simplify even further.

Solution 2:[2]

void* are pointers to memory that can hold any data of any type that can fit in it. You don't want to leave your void* uncast because you cannot dereference it until it is at least implicitly cast to a pointer to a complete type.

To make a bitmap for a data field in one contiguous memory region, you want to create a structure with bitmap and data field members, and initialize a pointer to that structure with the return value of the mmap() call.

Here is a short example:

#define CHUNK_SIZE 2048 //Pick whatever size you're mmaping (at least 16 bytes)

//One whole byte of bitmap and the 8 8-byte words it can map take up 65 bytes
#define MAP_LEN (CHUNK_SIZE % 65 ? CHUNK_SIZE / 65 + 1 : CHUNK_SIZE / 65)
//If MAP_LEN is not divisible by 8, we need padding between end of bitmap and beginning of data
#define DATA_LEN (MAP_LEN % 8 ? (CHUNK_SIZE - MAP_LEN - 8 + (MAP_LEN%8)) / 8 : (CHUNK_SIZE-MAP_LEN) / 8)

//This struct describes the layout of the whole mmap()ed region
struct chunk{
  uint8_t bitmap[MAP_LEN];  //Bitmap
  uint64_t data[DATA_LEN];  //8-byte words being mapped
};

int main(){
  struct chunk *mem = mmap(NULL,CHUNK_SIZE,/*Whatever your other mmap() parameters are*/);
  //Ensure mmap() didn't return (void*)-1
  memset(mem,0,CHUNK_SIZE); //This is only necessary if not mapped anonymously
  //Only the bitmap strictly must be cleared

  //Then store words like so
  mem->data[5] = 0xABADCAFE; //#5<-value (5 must be less than DATA_LEN)
  mem->bitmap[5/8] |= 1<<(5%8); //Put a 1 in the proper bit in the bitmap

  //And clear the bit when you're finished with its word
  mem->bitmap[5/8] &= ~(1<<(5%8));
}

Note: The above example uses the MAP_LEN and DATA_LEN macros at compile-time to calculate the greatest possible number of 8-byte words that can be stored and mapped within some CHUNK_SIZE number of bytes with the assumption that the alignment requirement of an 8-byte word is an 8-byte boundary, and on the condition that the bitmap must be the first thing in the allocated space, as per OP's prompt.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2