c: size of void* - c

I'm a bit confused with a void* pointer in C. Especially after reading this question: Is the sizeof(some pointer) always equal to four?, where one person says there is no guarantee that sizeof(int *) == sizeof(double *)
My question is: is there a guarantee of sizeof(void*) >= sizeof(any other pointer type)?
In other words, can I always assign a some_type* pointer to a void* pointer and then get it back as some_type*?

Only data pointers. void * can hold any data pointer, but not function pointers.
Here is a C FAQ.
void *'s are only guaranteed to hold object (i.e. data) pointers; it
is not portable to convert a function pointer to type void *. (On some
machines, function addresses can be very large, bigger than any data
pointers.)
As for the first part, yes, different types can have pointers of different sizes:

The value stored in the pointer is an address to memory. If you're on a 32-bit system, that pointer into memory is going to be 32 bits (or four bytes) long. If you're on a 64-bit system, that pointer into memory is going to be 64 bits (or eight bytes) long.
The size of the data that holds the location in memory has nothing to do with the size of the data represented at that location in memory.
As for how a char * differs from a double *, the char * can point to any location, but the double * has to point to something along an eight-byte boundary. Larger data has to be aligned according to the rules of the processor you're on. So, pointers to small data are not generally compatible with pointers to large data (e.g. you shouldn't point a double * pointer to a char * address); but you're save going in the other direction (e.g. you can point a char * pointer to a double * address).

Related

c fixed memory pool implementation

I'm trying to implement a fixed memory pool (first-fit free list)
my struct is:
struct mempool {
void* data;
int offset;
};
data is divided into 8byte blocks, 4 bytes pointing to next offset and 4 bytes data. offset points to the first free block. I'm trying to understand why accessing the first block is done by:
int* address = (int*)((int)&pool->data + pool->offset);
especially the (int)&pool->data part. Isn't pool->data already a pointer? why do I need its address to perform arithmetic and shift to the offset?
I'm trying to understand why accessing the first block is done by:
int* address = (int*)((int)&pool->data + pool->offset);
especially the (int)&pool->data part. Isn't pool->data already a
pointer?
Yes, pool->data is a pointer. And one can obtain the address of a pointer, so there's nothing inherently wrong with that. The result in this case has type void **.
Moreover, given that data is the first member of struct mempool, &pool would point to the same address. Although the latter has a different type (struct mempool *), that's probably mooted by the fact that the code performs a conversion to type int.
why do I need its address to perform arithmetic and shift to
the offset?
The effect is to compute an address relative to the location of the data pointer itself, rather than relative to its target. Furthermore, the cast to type int suggests that the offset is measured in bytes. That aspect of it is a bit unsafe, however, because it is not guaranteed that type int is large enough to support round-trip conversion from pointer to int to pointer.
This all seems consistent with your characterization of the pool having metadata adjacent to the data, but it remains unclear what purpose the data pointers serve.
Overall, although I'm not convinced of the correctness or efficacy of the minimal code presented. If it in fact serves the purpose for which it is intended, relative to the structure definition presented, then this variation should do so better and more clearly:
int* address = (int*)((char *)&pool + pool->offset);
That avoids the question of an integer type that can represent pointers (although there is one in the form of intptr_t). The cast to char * accounts for the fact that pointer arithmetic is performed in units the size of the pointed-to type, and the offset seems to be expressed in one-byte units.
You code does not seem correct. You are adding pool->offset to the address of pool->data field rather that to the address stored in pool->data field. I would suggest fixing like this:
int* address = (int *)pool->data + pool->offset;
in case your offset is in 4-byte chunks, or like this:
int* address = (int *)((char *)pool->data + pool->offset);
in case your offset is in bytes.
pool->data + pool->offset wouldn't be possible because you can't do pointer arithmetic on void pointers - that isn't valid C. Pointer arithmetic also assumes that the underlying type of this all is an array.
&pool->data gives the address of the pointer itself, which happens to be the address of the struct. The type void**. You can't do arithmetic on that either.
Therefore the naive, bad solution here is to cast the pointer to an int and then do simple addition. That doesn't work either, because int is not guaranteed to be able to hold the contents of a pointer. uintptr_t should have been used instead of int.
And finally, accessing that chunk of memory through int* then de-referencing it is only possible if what's stored there is already regarded as type int by the compiler. If not, it invokes undefined behavior, What is the strict aliasing rule?.
Summary: this is quite questionable code and there's many better ways to implement it.

Getting a pointer to a memory address from a different pointer C

I'm writing my own memory allocater. I'm getting a pointer to mapped memory from mmap. From there, I want to be able to get a pointer to a different part of that mapped memory (like x bytes away from the current pointer). How can I do this? Memory management is very confusing to me.
mmap gives you a void* and C doesn't allow pointer arithmetic with those, but you can cast it to char* and then just add the number of bytes you want, e.g. mypointer + 16.
If you cast the pointer to a larger type (like int*), pointer arithmetic adds multiples of the size of that type. For example, if you add 16 to an int*, you're adding enough bytes for 16 int values (so 64 bytes, assuming sizeof(int) is 4).

How does memcpy works with void pointers?

I am trying to memcpy from one ptr to another. I know the size that I want to copy. Both the destination and source pointers are void pointers. Is this valid? Does it actually copy the ELEMENT_SIZE (integer like 128) from source to the destination? I know this is not the most ideal thing to do. But I want to know if this works.
memcpy(to_add, element_ptr, ELEMENT_SIZE);
Does it actually copy the ELEMENT_SIZE (integer like 128) from source
to the destination?
Yes, If you know the size information,then its working fine.
See the reference link : http://www.cplusplus.com/reference/cstring/memcpy/
Parameter descriptions for memcpy from the documentation:
void * memcpy ( void * destination, const void * source, size_t num );
destination: Pointer to the destination array where the content is to be copied,
type-casted to a pointer of type void*.
source: Pointer to the source of data to be copied, type-casted to a pointer of type const void*.
num: Number of bytes to copy. size_t is an unsigned integral type.
memcpy simply takes num bytes starting from the address source and copies them to memory starting at address destination.
A pointer is a fixed length memory address, regardless of type. It does not matter whether the pointer is char * (points to character data), int * (points to integer data), or void * (points to data of unknown type), it still just points to memory.
Because memcpy copies an explicit number of bytes, the type of data being pointed to is irrelevant; it just need memory addresses to data.
It does not matter what pointer it is really. It is a very plain process of having two memory addresses and engaging a copy.

Explain variable declaration in C

I found this declaration in a C program
char huge * far *p;
Explanation: p is huge pointer, *p is far pointer and **p is char type
data variable.
Please explain declaration in more detail.
PS: I'm not asking about huge or far pointer here. I'm a newbie to programming
**p is character.Now a pointer pointing to address of this character will have value &(**p). Again if you want to take pointer to this pointer then next will be &(*p) and result will be p only.
If you read below sentence from right to left, you will get it all
p is huge pointer, *p is far pointer and **p is char type data variable.
In a nutshell virtual addresses on an Intel x86 chip have two components - a selector and an offset. The selector is an index into a table of base addresses [2] and the offset is added onto that base address. This was designed to let the processor access 20 bit (on a 8086/8, 186), 30 bit (286) or 46 bit (386 and later) virtual address spaces without needing registers that big.
'far' pointers have an explicit selector. However when you do pointer arithmetic on them the selector isn't modified.
'huge' pointers have an explicit selector. When you do pointer arithmetic on them though the selector can change.
Huge and far pointers are not part of standard C. They are borland extensions to the C language for managing segmented memory in DOS and Windows 16/32bit. Functionally, what the declaration says is **p is a char. That means "dereference p to get a pointer to char, dereference that to get a char"
In order to understand C pointer declarator semantics try this expression instead:
int* p;
It means p is a pointer to int. (hint: read from right to left)
int* const p;
This means p is a const pointer to int. (so you can't change the value of p)
Here's a proof of that:
p= 42; // error: assignment of read-only variable ā€˜pā€™
Another example:
int* const* lol;
This means lol is a pointer to const pointer to int. So the pointer which lol points at cannot point at another int.
lol= &p; // and yes, p cannot be reassigned, so we are correct.
In most cases reading from right to left makes sense. Now read the expression in question from right to left:
char huge * far *p;
Now the huge and far are just behaviour specifiers for pointers created by borland. What it actually means is
char** p;
"p is a pointer to pointer to char"
That means whatever p points to, points to a char.
Back in the 16-bit days on 8086, it would have declared a 32-bit pointer to a "normalized" 32-bit pointer to char (or to the first of an array thereof).
The difference exists because 32-bit pointers were composed of a segment number and offset between that segment, and segments overlapped (which meant two different pointers could point to the same physical address; example: 0x1200:1000 and 0x1300:0000). The huge qualifier forced a normalization using the highest segment number (and therefore, the lowest possible offset).
However, this normalization had a cost performance-wise, because after each operation that modified a pointer, the compiler had to automatically insert a code like this:
ptr = normalize(ptr);
with:
void huge * normalize(void huge *input)
{
unsigned long input2 = (unsigned long)input;
unsigned short segment = input >> 16;
unsigned short offset = (unsigned short)input;
segment += (offset >> 4);
offset &= 0x000F;
return ((unsigned long)segment) << 16 | offset;
}
The upside was the advantage of using your memory like it was flat, without worrying about segments and offsets.
Clarification to the other answers:
The far keyword is non-standard C, but it is not just an old obsolete extension from ancient PC days. Today, there are many modern 8 and 16 bit CPUs that uses "banked" memory to extend the amount of addressable memory beyond 65k. Typically they use a special register to pick a memory bank, effectively ending up with 24-bit addresses. All small microcontrollers on the market with RAM+flash memory > 64kb use such features.

casting of an address

You have an operating system, which has 2 functions dealing with memory allocation:
void *malloc( int sz ) // allocates a memory block sz bytes long
void free( void *addr ) // frees a memory block starting at addr
// (previously allocated by malloc)
Using these functions, implement the following 2 functions:
void *malloc_aligned( int sz ) // allocates a memory block sz bytes long,
// aligned to an address divisible by 16
void free_aligned( void *addr ) // frees a memory block starting at addr
// (previously allocated by malloc_aligned)
in the solution there is the following part:
void * aligned_malloc(size_t size){
unsigned char *res=malloc(size+16);
unsigned char offest=16-((long)res%16);
What I don't understand is: Why do we need to use unsigned char and why and what we achieve using 16-((long)res%16); and what is the purpose of (long)res in this case?
You can't do pointer arithmetic on "void *", because void has no size.
When adding to a pointer or subtracting to it, it's always done in units of sizeof(*p). Meaning - if you add one to an int pointer, its value grows by 4 (because the size of an integer is 4). So when you add to a void pointer, it should grow by the size of a void. But void has no size.
However, some compilers are willing to do arithmetic on void *, and they treat it like char *. With these compilers, you could implement these functions without casting. But it isn't standard.
Another point is that not all operators are applicable for pointers. Addition and subtraction are, but multiplication, division and modulus are not. So if you want to test the low bits of a pointer, to know if it's aligned, you cast it to a long.
Why long? The assumption is that long is as large as a pointer, which is true in Linux, but not in Windows. The right type is uintptr_t. However, if you're only interested in the low bits, it doesn't matter if you lose the high bits while casting. So a cast to int would have worked too.

Resources