address=data via macro define - c

#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.

Related

Parentheses around structure variable with asterisk operator

Consider the if statement:
if (((DbSignal*) ev->newVal.buff)->sig)
Where DbSignal is a structure.
Why is DbSignal within brackets and what is the asterisk operator doing in this case?
It is the cast: ev->newVal.buff is casted to pointer to DbSignal. Then this pointer is being dereferenced (sig member accessed)
What is the type cast: What exactly is a type cast in C/C++?
The syntax (DbSignal*) is a typecast. It converts one type to another.
In this case, the operand of the cast is ev->newVal.buff which presumably is a pointer to a character buffer. This pointer is converted to a pointer to DbSignal via the cast. The result is then dereferenced and the sig member is accessed.
We have ev which is a pointer in this case.
it points to a struct containing the variable newVal which contains a buff pointer.
So we have ev->newVal.buff
Here buff is either a char* or void* (a series of bytes, but apparently has some layout). Meaning that the memory it points to could potentially be interpreted in different ways.
By your example, we know that buff has a certain layout, corresponding to the DbSignal struct.
So in order to access ->sig we have to cast this .buff to DbSignal, basically telling that we want to interpret that memory region with the layout described by DbSignal.
Hope this gives some context.

How is this dereferenced?

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.

What does this line of code mean (Bitwise Operator)

#define LODWORD(x) (*((unsigned int*)&(x)))
I'm translating C code to python and can't quite get this. If anyone can explain how to read this or what it means it'd be greatly appreciated.
It's a macro for getting the lower DWORD ( 32bits ) of a 64 bit variable, there's most likely an associated HIDWORD macro as well to get the higher 32 bits. Other comments have pointed out some flaws with the macro, but it's a fairly common idiom for accomplishing this.
Some equivalent Python code might be:
def LODWORD(x):
return x & 0xFFFFFFFF
&(x) // get address of `x` as a pointer to whatever x is
(unsigned int*)(...) // cast it to a pointer to `unsigned int`
*(...) // then read that address' contents as if it was `unsigned int`
I'd use union if really needed, and only if I knew the CPU architecture, otherwise this is very very unsafe :P
First by using #define defines a macro that does substitution. It is a macro with an argument, a so-called "function-like macro".
After the #define when an expression LODWORD(whatever you write here) occurs it will be replaced by (*((unsigned int*)&(whatever you write here))) before the code is fed into the compiler. This is called "macro expansion". The compiler will only see expanded expressions.
The macro expanded expression of LODWORD(foo) does the following:
(foo) is common idiom in macros: Put arguments into parentheses to avoid operator precedence errors.
&(foo) means "the address of (foo)" (a "pointer"). This creates a value that represents the memory location of foo. It is of type "pointer to the type of foo" .
(unsigned int*)&(foo) converts "the adress of foo" into "the address of the unsigned int foo". The operator (insigned int*) is called a "cast operator". It changes the result type "pointer to the type of foo" into "pointer to an unsigned int".
((unsigned int*)&(foo)) overrides operator precedence. Now you have "pointer to an unsigned int at the memory location of foo.
*((unsigned int*)&(foo)) returns the value of the unsigned int at the memory location of foo (even if foo is not an unsigned integer and even if that memory location violates alignment requirements for an unsigned int).
(*((unsigned int*)&(foo))) is yet another common idiom in macros: Put the entire expression into parentheses to avoid operator precedence errors. Then the macro can always be used as if it was a function.

Why do I get warnings when I try to assign the address of a variable to a pointer that was declared to point to a variable of a different type?

Take a look at the following program. What I don't understand is why do I have to cast the address of the variable x to char* when it actually would be absolutely useless if you think about it for a second. All I really need is only the address of the variable and all the necessary type information is already in place provided by the declaration statement char* ptr.
#include <stdio.h>
int main(void) {
int x = 0x01020309;
char* ptr = &x; /* The GCC compiler is going to complain here. It will
say the following: "warning: initialization from
incompatible pointer type [enabled by default]". I
need to use the cast operator (char*) to make the
compiler happy. But why? */
/* char* ptr = (char*) &x; */ /* this will make the compiler happy */
printf("%d\n", *ptr); /* Will print 9 on a little-endian machine */
return 0;
}
The C Standard, 6.2.5 Types, paragraph 28 states:
A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and
alignment requirements. All pointers to structure types shall have
the same representation and alignment requirements as each other.
All pointers to union types shall have the same
representation and alignment requirements as each other.
Pointers to other types need not have the same representation or alignment requirements.
Since different types of pointers can have differing implementations or constraints, you can't assume it's safe to convert from one type to another.
For example:
char a;
int *p = &a
If the implementation has an alignment restriction on int, but not on char, that would result in a program that could fail to run.
This is because pointers of different types point to blocks of memory of different sizes even if they point to the same location.
&x is of type int* which tells the compiler the number of bytes (depending on sizeof(int)) to read when getting data.
Printing *(&x) will return the original value you entered for x
Now if you just do char* ptr = &x; the compiler assigns the address in &x to your new pointer (it can as they are both pointers) but it warns you that you are changing the size of the block of memory being addressed as a char is only 1 byte. If you cast it you are telling the compiler that this is what you intend.
Printing *(ptr) will return only the first byte of the value of x.
You are correct that it makes no practical difference. The warning is there to inform you that there might be something fishy with that assignment.
C has fairly strong type-checking, so most compilers will issue a warning when the types are not compatible.
You can get rid of the warning by adding an explicit cast (char*), which is you saying:
I know what I'm doing, I want to assign this value to my char* pointer even if the types don't match.
Its just simple as you assign integer type to character. similarly you are trying to assign integer type pointer to character type pointer.
Now why is so because this is how c works, if you increment a character pointer it will give you one byte next address and incrementing integer pointer will give you 2 byte next address.
According to your code, x is of type int. So the pointer that points to x should be of type int *. Compiler gives such error because you use a pointer which is not int *.
So make your pointer either int *, or void * then you don't need cast.

De-referencing pointer to a volatile int after increment

unsigned int addr = 0x1000;
int temp = *((volatile int *) addr + 3);
Does it treat the incremented pointer (ie addr + 3 * sizeof(int)), as a pointer to volatile int (while dereferencing). In other words can I expect the hardware updated contents of say (0x1012) in temp ?
Yes.
Pointer arithmetic does not affect the type of the pointer, including any type qualifiers. Given an expression of the form A + B, if A has the type qualified pointer to T and B is an integral type, the expression A + B will also be a qualified pointer to T -- same type, same qualifiers.
From 6.5.6.8 of the C spec (draft n1570):
When an expression that has integer type is added to or subtracted from a pointer, the
result has the type of the pointer operand.
Presuming addr is either an integer (variable or constant) with a value your implementation can safely convert to an int * (see below).
Consider
volatile int a[4] = [ 1,2,3,4};
int i = a[3];
This is exactly the same, except for the explicit conversion integer to volatile int * (a pointer to ...). For the index operator, the name of the array decays to a pointer to the first element of a. This is volatile int * (type qualifiers in C apply to the elements of an array, never the array itself).
This is the same as the cast. Leaves 2 differences:
The conversion integer to "pointer". This is implementation defined, thus if your compiler supports it correctly (it should document this), and the value is correct, it is fine.
Finally the access. The underlying object is not volatile, but the pointer/resp. access. This actually is a defect in the standard (see DR476 which requires the object to be volatile, not the access. This is in contrast to the documented intention (read the link) and C++ semantics (which should be identical). Luckily all(most all) implementations generate code as one would expect and perform the access as intended. Note this is a common ideom on embedded systems.
So if the prerequisites are fulfilled, the code is correct. But please see below for better(in terms of maintainability and safety) options.
Notes: A better approach would be to
use uintptr_t to guarantee the integer can hold a pointer, or - better -
#define ARRAY_ADDR ((volatile int *)0x1000)
The latter avoids accidental modification to the integer and states the implications clear. It also can be used easier. It is a typical construct in low-level peripheral register definitions.
Re. your incrementing: addr is not a pointer! Thus you increment an integer, not a pointer. Left apart this is more to type than using a true pointer, it also is error-prone and obfuscates your code. If you need a pointer, use a pointer:
int *p = ARRAY_ADDR + 3;
As a personal note: Everybody passing such code (the one with the integer addr) in a company with at least some quality standards would have a very serious talk with her team leader.
First note that conversions from integers to pointers are not necessarily safe. It is implementation-defined what will happen. In some cases such conversions can even invoke undefined behavior, in case the integer value cannot be represented as a pointer, or in case the pointer ends up with a misaligned address.
It is safer to use the integer type uintptr_t to store pointers and addresses, as it is guaranteed to be able to store a pointer for the given system.
Given that your compiler implements a safe conversion for this code (for example, most embedded systems compilers do), then the code will indeed behave as you expect.
Pointer arithmetic will be done on a type that is volatile int, and therefore + 3 means increase the address by sizeof(volatile int) * 3 bytes. If an int is 4 bytes on your system, you will end up reading the contents of address 0x100C. Not sure where you got 0x1012 from, mixing up decimal and hex notation?

Resources