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.
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 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.
I have the following variable
uint32_t Value = 0x80
0x80 represents an address in the memory e.g.
// Write 2 at address 0x80
*(uint32_t*)((uint32_t)0x80) = 2;
How can i cast Value to a Pointer, so it points to 0x80?
uint32_t *Pointer = ?? Value;
This:
(uint32_t*)(uint32_t)Value;
returns:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
To handle integer to object pointer conversion, use the optional integer uintptr_t or intptr_t types. Function pointers are a separate matter.
The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer C11dr 7.20.1.4 1
uintptr_t
Then convert the void * to the desired type.
#include <stdint.h>
uintptr_t Value = 0x80;
uint32_t *Pointer = (void *) Value;
If 0x80 was not derived from a valid uint32_t *, the result in undefined behavior (UB). Yet it sounds like OP is on a platform with memory mapped data locations.
I will spell it out for you: given
uint32_t Value = 0x80;
you want
*((uint32_t *)(uintptr_t)Value) = 2;
The type uintptr_t, if it exists, is guaranteed to be castable to and from arbitrary pointer types without loss of information. It is not guaranteed to exist, but on platforms where it doesn't exist, what you're trying to do cannot safely be done without a great deal more information.
No other type is officially guaranteed to have this property; however, "cpp plus 1" is correct that size_t usually also does. I would go so far as to say that any ABI for a flat-memory architecture, that doesn't make size_t have this property, was specified incorrectly, but they do exist and sometimes you have to work with them.
It would be better to declare Value with a pointer type in the first place:
uint32_t *const Value = (uint32_t *)(uintptr_t)0x80;
because then you only have to write the casts when you initialize it, not when you use it,
*Value = 2;
and you probably have a bunch of places where you use it. This also avoids a potential problem if it happens that sizeof(uintptr_t) < sizeof(uint32_t), as uint32_t is never involved in the address arithmetic; the compiler may complain if the cast from 0x80 to uintptr_t actually truncates the constant, but that shouldn't ever happen with the real memory addresses you are accessing this way.
What does it mean to convert an integer value to a void* or viceversa from a memory point of view?
My understanding is void* is an address to a block of memory of unspecified length.
This seems to be something like comparing apple with oranges.
int myval = 5;
void* ptr = (void*)myval;
printf("%d",(int)ptr);
I realized that I should have given the exact context where this is used.
int main(int argc, char* argv[]) {
long thread; /* Use long in case of a 64-bit system */
pthread_t* thread_handles;
/* Get number of threads from command line */
if (argc != 2) Usage(argv[0]);
thread_count = strtol(argv[1], NULL, 10);
if (thread_count <= 0 || thread_count > MAX_THREADS) Usage(argv[0]);
thread_handles = malloc (thread_count*sizeof(pthread_t));
for (thread = 0; thread < thread_count; thread++)
pthread_create(&thread_handles[thread], NULL, Hello, (void*) thread);
printf("Hello from the main thread\n");
for (thread = 0; thread < thread_count; thread++)
pthread_join(thread_handles[thread], NULL);
free(thread_handles);
return 0;
} /* main */
/*-------------------------------------------------------------------*/
void *Hello(void* rank) {
long my_rank = (long) rank; /* Use long in case of 64-bit system */
printf("Hello from thread %ld of %d\n", my_rank, thread_count);
return NULL;
} /* Hello */
This code is from Peter Pachecho's book on Parallel programming.
Casting int to void * is rather meaningless and should not be done as you would be attempting to cast a non-pointer to a pointer. Quoting the C99 standard, section 6.3.2.3 item 5:
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.
You could cast int * to void * (any pointer is convertible to void * which you can think of like the "base type" of all pointers).
Casting void * to int is not portable and may be completely wrong depending on the platform you use (e.g. void * maybe 64 bits wide and int may only be 32 bits). Quoting the C99 standard again, section 6.3.2.3 item 6:
Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.
To solve this, some platforms provide uintptr_t which allows you to treat a pointer as a numeric value of the proper width.
Both void* pointer (or any pointer for that matter) and int are, roughly speaking, numbers. They may be of different bitsize, but it is unlikely that pointer is smaller than int, so that makes the operation reversible. Of course, it's illegal and you should never dereference the pointer that has no valid location to point to.
The C standard specifies that it must be possible to convert a void pointer to an integral type such that converting the integral type back to a void pointer will yield the same pointer. I'm not sure if it requires that converting a null pointer to an integer yield the value zero, or if only numeric literal zeroes are recognized as special. On many implementations, the integer value represents a hardware address, but the standard makes no such guarantee. It would be entirely possible that on hardware which included a special trap for hardware address 0x12345678, converting a pointer to an integer would subtract 0x12345678 from the hardware address, and converting an integer to a pointer would add 0x12345678 back in (thus an integer value of zero would represent a null pointer).
In many cases, particularly when developing for embedded controllers, the compiler vendor will explicitly specify what hardware address will be accessed when converting a particular integer value to a pointer type. On processors with a single linear address space, converting an integer value 0x12345678 to a pointer would generally yield a pointer which refers to address 0x12345678; the hardware reference manual would indicate if there was anything special about that location. On processors with more 'interesting' address spaces, it may be necessary to use something other than the hardware address as the pointer. For example, on antique IBM PC computers, the display buffer was mapped at hardware address 0xB8000, but in most compilers, the address would be expressed as (short far*)0xB8000000.
This is quite like comparing apples and oranges. The only way that this code works is because you are explicitly casting it back and forth.
The C compiler is just copying the bytes from the int into the space for the pointer and back, just like how you can hold a char in an int.
This could even cause your number to be messed up if for some reason an 'int' is longer than a 'void *' on your platform.
If you actually do want have a number to convert from integers into pointers and back, look into intptr_t. That type is actually designed to store both integers and pointers.
It is useful to be able to cast a pointer to integer type for pointer arithmetic. For instance, the offsetof() macro, which calculates the offset of a member within a structure, needs this kind of conversion.
However, it must be ensured that the primitive type used for this is able to handle a pointer: here, for 64 Linux for instance, when using gcc, this is not the case: void * has size 8, an int has size 4.
The offsetof macro is defined as such:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
It is used prominently in the Linux kernel's doubly linked list implementation, very simply defined as:
struct list_head { struct list_head *prev, *next; }
This struct is embedded within kernel structures, as in:
struct something {
//...
struct list_head list;
//...
}
When walking a list, the code needs to grab a pointer to the encoding structure. This is done as this (simplified definition):
#define container_of(ptr, type, member) \
(type *)((char *)ptr - offsetoff(type, member))
#define list_entry(list, type, member) \
container_of(list, type, member)
And in the code, you will very often see:
struct something *s;
list_for_each(listptr, somehead) {
s = list_entry(listptr, struct something, list);
//...
}
which would simply not be doable without this kind of macro and pointer arithmetic. But it is very dependent on the toolchain.
It would be like comparing apples with oranges if any attempt was being made to make any comparison. But there isn't. Basically, in the majority of architectures out there, an int can be casted to a void pointer without the loss of any information, and a void pointer can also be casted back to an int, again without the loss of any information. Of course, you should not try dereferencing that pointer, because it does not point to any meaningful memory location: it is just a variable containing the same bit-pattern as the bit pattern that the integer used to contain before the cast.
#define PORTC *(unsigned char volatile *)(0x1003)
#define DDRC *(unsigned char volatile *)(0x1007)
So I've been trying to read some stuff about embedded C. Initially I thought this macro was a pointer-to-pointer type but then I soon assumed the last star is actually a dereference rather than a type-cast, am I correct? Dereferencing to the location 0x1003/0x1007.
It is used like: PORTC = <some hex value>
Question is what makes this different from a pointer type-cast? Is there some sort of 'provision' in the C specifications? Or am I just an idiot...
Also I don't quite know how to phrase this and so I couldn't do a quick search first...
It's just the way the C grammar is defined.
To be a cast, the expression needs parenthesis: (type)sub-expression casts sub-expression to type type.
Your example, *(unsigned char volatile *)(0x1003) is composed of 2 sub-expressions:
a "lonely" star: *
a cast: (unsigned char volatile *)(0x1003)
The cast is composed of the type inside () and a value.
So, the whole expression is interpreted as a pointer, then de-referenced to set the memory area pointed to.
No, it is quite a cast.
First, the memory location (as integer) is cast into an appropriate pointer which is then dereferenced.
That code is basically equivalent to: Put <some hex value> in the memory at the address (0x1003) (or whatever the value is). In some embedded devices (and not only) ports are mapped at memory locations.
The cast instructs the compiler that the memory addresses 0x1003 and 0x1007 are to be treated as unsigned char volatile * pointers, and the * dereferencing operator acts on that pointer to fetch the pointed-to value, which in this case is 1 byte.
Applying the unary * makes this expression a valid lvalue (it wouldn't be so without it) which means that it is something you can assign to.