I have a void* in plain C that I'm using while walking through some unstructured data, and I'd like to cast with dereference and autoincrement as I go. I would like to write the following:
void* ptr = /*something*/;
uint16_t i = *((uint16_t*) ptr)++;
The compiler objects and tells me "lvalue required as increment operand", but I guess I thought that a pointer cast as a pointer would still qualify as an lvalue.
Clearly my intent is for ptr to now point two bytes beyond where it pointed before. I can't remove the parentheses around the cast of ptr because ++ has higher precedence than the cast, so this won't work as I want it to:
int i = *(uint16_t*) ptr++;
I could of course do my own incrementing, like the following, but I was hoping for something elegant and concise:
int i = *(uint16_t) ptr;
ptr += sizeof(uint16_t);
What's a good way to do this?
It would be simplest to write:
uint16_t *uptr = ptr;
uint16_t i = *uptr++;
ptr = uptr; // if required
You might be able to restructure the larger code to have a uint16_t * as much as possible, removing the need for so many conversions.
Incrementing a pointer cast to a different type has been disallowed for a long time, probably since C89. The reason is that the conversion from one type of pointer to another type can change the representation, and thus might not refer to the same object.
You must split the expression into 2 statements:
void *ptr = /*something*/;
uint16_t i = *(uint16_t*)ptr;
ptr = (uint16_t*)ptr + 1;
Or if context commands for a single expression, you could use this hack:
uint16_t i = ((uint16_t*)(ptr = (uint16_t*)ptr + 1))[-1];
Or this one if you want to obfuscate even more:
uint16_t i = (-1)[(uint16_t*)(ptr = (uint16_t*)ptr + 1)];
void *ptr;
*(*(uint16_t **)&ptr)++;
Taking the address to the pointer (a void ** type) casting it to uint16_t **, dereference it, now you have a valid lvalue you can increment and dereference normally.
Related
Not sure if I'm phrasing the question properly nor how to best explain what I'm trying to have answered so bear with me.
When defining a microcontroller register, you would write something like this:
#define io_register (*(volatile unsigned char *)0x25)
I also found this line of code here: Pass a hex address to a Pointer Variable
int *pointer = (int *) 0x00010010;
I understand that a pointer that points at an int is being declared left of the = sign, but why is there a typecast *(int ) right of it?
Same with the #define, I understand that the value at 0x25 is being dereferenced but why am I not able to write it like this:
#define io_register *(0x25)
or
int *pointer = 0x25;
What am I missing here? Please feel free to rephrase or correct any mistakes I've made, still trying to wrap my head around pointers and registers.
An important prerequisite of any assignment operation is data type compatibility. In other words, the data type of the equation's (int *pointer = 0x25;) LHS (int *pointer) must be compatible with whatever data type results from the evaluation of the equation's RHS (0x25).
For example, if both LHS and RHS are int types, then there will be no problem assigning the integer value of RHS to LHS.
But, in this expression:
int *pointer = 0x25;
you have int * data type in LHS and int data type in RHS. So, there's an incompatibility between LHS & RHS. That's why you need to cast RHS to (int *).
The cast suppresses the warning. That is its role in those statements. Otherwise it will be casted implicit way, and warning omitted. No difference in the code or program execution.
#define io_register *(0x25)
*(0x25) will not be a pointer in any circumstanes and io_register when used means : multiply by 0x25.
int x = 10 io_register;
which means: int x = 10 *(0x25);
With
int *pointer = (int *) 0x00010010;
You are telling the pointer to point to an absolute address in memory, the value at that address can be dereferenced with *pointer.
With
int *pointer = 0x25;
The compiler does not like that because 0x25 is an integer but pointer is not an integer, it is an integer pointer.
The cast is needed because 0x00010010 is not a pointer but an integer (it is the first type among int, unsigned int or long int that can represent the value 65552) .
Only integer constant expressions having value of 0 can be converted to a pointer implicitly (i.e. without a cast); the resulting pointer would be a null pointer.
You can naturally write
#define io_register *(0x25)
but you cannot use that io_register to access memory at address 0x25, because that 0x25 is not a pointer - it is an integer.
In C one does not really access addresses; instead one dereferences pointers to get lvalues that designate an object, and then get the value of that object, or a set a new value to it.
I'm following a tutorial, where they want to write a particular value (0x0403) to register (at address 0x04000000)
As per my knowledge, this could be done like this,
unsigned int 32 *ptr;
ptr = 0x04000000
*ptr = 0x403
However, they are doing following:
#define REG_DISP *((volatile uint32*)(0x04000000))
#define VIDEOMODE_3 0x0003
#define BGMODE_2 0x0400
int main()
{
REG_DISP = VIDEOMODE_3 | BGMODE_2;
while(1){}
}
Now, I have following questions:
Can we use pointers without declaring any variables?
Why pointer to a pointer is used? Is it because, we cannot do ptr = 0x04000000?
Just a remark. All this can only be implementation defined, because the language itself has no concept of registers living at well known addresses.
The standard just says at 6.3.2.3 Pointers ยง5 (emphasize mine):
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
That means that this is valid C, provided the implementation allows it to make sense:
unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;
It just uses a named pointer to access the specific address. It can be done without naming the pointer that way:
* ((unsigned int *) 0x04000000) = 0x403;
Let us see how it works:
(unsigned int *) 0x04000000 converts an unsigned int to a pointer to unsigned int
* ((unsigned int *) 0x04000000) dereferences that pointer
* ((unsigned int *) 0x04000000) = 0x403; assigns a value to the pointed variable
As you want to access a physical register, you need to ask the compiler to immediately write the value instead of keeping it in an internal register which could be allowed per the as if rule. That is the meaning of the volatile qualifier. As it is dedicated to a specific implementation, it is perfectly legal, provided you can be sure that unsigned int has 32 bits in that implementation, to write
volatile unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;
or
* ((volatile unsigned int *) 0x04000000) = 0x403;
Ad. 1: C allows to convert an integral value to a pointer and vice versa. Weather you assign the (intermediate) conversion to a variable or not does not matter. Code part (volatile uint32*)(0x04000000) actually converts integral literal 0x0400000 to a pointer of type uint32*; Note the volatile, which turns off any compiler optimizations and lets the code actually access the respective memory whenever dereferened.
Ad 2: there is no pointer to pointer; *((volatile uint32*)(0x04000000)) just dereferences the pointer (which has been explained in (1).
I guess this is about GameBoy Advance development.
You can write to a memory address without declaring any variable, a pointer is a type of value which represents a memory address, you can write and read from it without the need to store it anywhere.
It's not a pointer to a pointer, it's a hardcoded address which is cast to a (volatile uint32*), and the macro adds the * operator in front just to save you from writing it, which is just confusing.
I'm working on a framework for GBA development right in these days, maybe you can pick some informations or code from there, mind that code is C++14 though.
I am failing to understand what the expression *(uint32_t*) does.
I have broken the statement down to an example that declares the parts so I can try and interpret what each one does.
uint32_t* ptr;
uint32_t num
*(uint32_t*)(ptr + num); // <-- what does this do?
I don't understand the last bit in the example, what happens when the expression *(uint32_t*)(ptr + num); executes during runtime?
uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1.
This
uint32_t* ptr;
declares a pointer of type uint32_t*, but the pointer is uninitialized, that
is, the pointer does not point to anywhere in particular. Trying to access memory through that pointer will cause undefined behaviour and your program might crash.
This
uint32_t num;
is just a variable of type uint32_t.
This
*(uint32_t*)(ptr + num);
ptr + num returns you a new pointer. It is called pointer arithmetic. It's like regular arithmetic, only that compiler takes the size of types into
consideration. Think of ptr + num as the memory address based on the original ptr pointer plus the number of bytes for num uint32_t objects.
The (uint32_t*) x is a cast. This tells the compiler that it should treat the expression x as if it were a uint32_t*. In this case, it's not even needed,
because ptr + num is already a uint32_t*.
The * at the beginning is the dereferencing operator which is used to access the memory through a pointer. The whole expression is equivalent to
ptr[num];
Now, because none of these variables is initialized, the result will be garbage.
However, if you initialize them like this:
uint32_t arr[] = { 1, 3, 5, 7, 9 };
uint32_t *ptr = arr;
uint32_t num = 2;
printf("%u\n", *(ptr + num));
this would print 5, because ptr[2] is 5.
uint32_t is defined in stdint.h, so one may need to include it
#include <stdint.h>
this header shall define uint32_t to be an unsigned integer type taking exactly 32 bits.
This doesn't really do anything. Let me give you a different example:
uint32_t data;
void *pointer = &data;
*(uint32_t *)pointer = 5;
First of all, void* means "generic" pointer. It can point to objects of any type.
Now, (uint32_t *) means "interpret pointer as a pointer to an object with type uint32_t.
The rest of the expression simply means "store 5 at the location stored by this pointer".
If you want to know what uint32_t is, that's an unsigned integer with exactly 32 bits. And pointer + num is the same as the adress of pointer[5].
This type of expression is usually used in type punning. If you're not familiar with type punning, the main idea is to bypass the type system so that you can treat something as a different type than it really is (ie treat an int a as double)
The main idea behind type punning is you take a pointer to a current variable and then pun it into a different type by casting it into a pointer of that type and then dereferencing it, hence the commonly used cast and dereference you are referring to ( *(uint32_t *) = cast to unsigned 32bit int pointer and then dereference).
As others have pointed out, your code "does nothing" because you are punning an int to an int, which has no effect. If you wanted to pun an int into a double however...
uint32_t num=5;
double& myvar=*(double*) #
Now you can manipulate nums memory as a double via myvar even though num is still an Int. This is a terrible idea and is just meant as a toy example of the use of punning.
Let's assume I have this code:
char *pointer;
unsigned int a;
pointer = a;
For me this doesn't generate any problems but I will receive the following warning:
assignment makes pointer from integer without a cast
Why is it better to use cast?
I'm using a 32 bit machine.
Edit:
By "this doesn't generate any problems", I was saying that it compiles and pointer stores the value of variable a.
Edit:
And variable a will actually store an address.
It's almost always better not to try to assign an integer value to a pointer at all. In the rare cases where such an assignment makes sense, a cast is not just better, it's required.
Pointers and integers are distinct types. In some cases it can make sense to mix them; in such cases you need a cast, because there is no implicit conversion between integers and pointers (other than the special case of 0, treated as a null pointer constant).
char *pointer;
int a; /* or unsigned int a, it's the same either way */
pointer = a;
This assignment is illegal (more precisely, a constraint violation). A conforming C compiler must at least warn about it. Many compilers, after printing a warning, will generate code that performs an implicit conversion, but that's not required by the language, and you shouldn't depend on it. My personal opinion is that compilers that do this aren't doing you any favors.
pointer = (char*)a;
This is legal; the cast tells the compiler to generate an conversion from int to char*. But the result of that conversion is implementation-defined, and very likely doesn't yield a meaningful result -- even if char* and int happen to be the same size.
(In the code in your question, a hasn't been initialized. I presume that's not the case in the real code you haven't shown us.)
What are you actually trying to accomplish?
Because in C:
pointer = a; // not valid in C: a is an int object
// pointer an object of pointer type
the statement is not valid, you need an explicit conversion (a cast) to convert a value to a pointer type.
pointer = (char *) a; // valid assignmnent
Some compilers are nice with you and will implicitly convert the int value to a pointer type (and add a warning!) but they are not required to do so and a compiler can refuse to compile your program.
% cat int-cast.c
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("sizeof char *: %zu\n", sizeof (char *));
printf("sizeof int: %zu\n", sizeof (int));
}
Then if compiled 32 or 64 bit the size of the types differ
% cc -m32 int-cast.c && ./a.out
sizeof char *: 4
sizeof int: 4
% cc -m64 int-cast.c && ./a.out
sizeof char *: 8
sizeof int: 4
And as Keith Thompson explicitly points out, even if they were guaranteed to be the same size, a cast would still be required, and the result would be at best implementation-defined.
In C a pointer is not only an address in memory, it is also a type:
pointer = memory size + type
The best way to understand this is to think about pointer arithmetic that prevent to do some arithmetics operations. For example, you can do:
int i;
int * ptr, ptr2;
ptr = &i; // Assign the address of an int to an int pointer
ptr2 = ptr + 2; // Shift the pointer of two int size further
i = ptr - ptr2; // Compute the number of slots between ptr and ptr2
But, you cannot do:
int i;
char c;
int * ptr;
char * ptr2;
ptr = &c; // The types are not matching, the compiler will complain
ptr = 2 * ptr; // This is not allowed by pointer arithmetic
ptr = ptr + ptr; // This is not allowed by pointer arithmetic
And so on...
But, what you have always to remember is that a pointer is not only a memory address. It is the combination of a memory address and a type.
I am studying C Language I need some explanation about a code segments,
int *p;
p = (int *) malloc(sizeof(int));
What does the (int *) means and whats really happening when you execute the above Code?
(int *) is a so called cast operator. It is used to convert the value on the right side of the operator to the type enclosed in parenthesis.
Here, it is used to convert the void * pointer returned by malloc() to an int *, i.e. a pointer to an integer.
This is a very bad usage, and you should not do it.
malloc has return type void*, which reads as pointer-to-void which means pointer-to-something.
p has type int*, so pointer-to-int. In order to assign the result of malloc into p, you need to convert int* into void* somehow.
If you write:
int* p = malloc(...)
the conversion happens automatically ("implicit conversion").
If you, for some reason, decide to write:
int* p = (int*) malloc(...)
the result is the same, but the conversion is explicit (i.e. a "cast").
Here's the documentation on malloc.
You're allocating a block of memory the size of an int (this value may change depending on the system/compiler combo).
The (int *) casts the right hand side as an int *, which isn't necessary in C, you just need the malloc.
int *p; // pointer to an integer
p = (int *) malloc(sizeof(int)); // assignment of enough memory for an integer
The (int *) part is called typecasting, you're telling the compiler:
"I know malloc() gives me a void *, but I'm going to assign it to something else".
There are useful reasons to typecast, but it can be dangerous too. In this case since malloc() returns a void * you don't need to typecast because it's automatically and safely converted to other pointer types.
Try this link man malloc
In C, there is no need of typecasting in mallocso write directly
p = malloc(sizeof(int));
FYI , this (int *) is nothing but the typecast. Since many functions return void*
so it needs to typecast in the respective type for further manipulations with pointers.
In case of malloc it's implicitely taken care of
(type) is called type cast operator in C.
suppose for example,
int a;
float b = 11.4;
You want to put the integral value of bin a. Use type casting
a = (int)b
Unwind already gave you the answer, but I want to expand on it a bit.
In C, some types are not compatible; you can't directly assign a value of type T to a variable of type Q; for example, you can't assign a pointer to int to a variable that's type pointer to double:
double *q;
int *p;
...
q = p; // will cause a diagnostic to be issued
If you really need to make that assignment, though, you can use a cast expression, which converts the value to the target type:
q = (double *) p;
This tells the compiler to convert the value of p to pointer to double and assign the result to q.
In the original, K&R version of C, malloc returned char *, so if you wanted to assign the result of malloc to a pointer of a different type, you had to apply the cast:
int *p = (int *) malloc(SIZE);
That changed in 1989, when the first C standard was introduced. That version introduced a void * type to act as a "generic" pointer type. Values of type void * can be assigned to other pointer types directly, without need of a cast. So, as of C89 and later, you can simply write
int *p = malloc(SIZE);
This was not only cleaner, it was also safer; if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope, the compiler would assume that malloc returned an int value and generate code accordingly. Since an int value can't be directly assigned to a pointer type, you would get a diagnostic. If you added the cast, however, that warning would be suppressed, and you would potentially have issues at runtime.
The 1999 standard got rid of the implicit int assumption, so that's no longer a real danger, but it's still better style to leave the cast off of a malloc call.