What does this C macro mean? - c

Looking at fm_transmitter source code, I came across this macro, which is used quite often.
#define ACCESS(base, offset) *(volatile unsigned*)((int)base + offset)
I guess its a sum of base and offset casted as int, then re-casted into unsigned pointer and then again pointer?

This macro provides access to an offset that is measured in bytes. You could rewrite it as
#define ACCESS(base, offset) *(volatile unsigned*)&((char*)base)[offset]
only that the original version does the arithmetic via the int type instead of the char* type.
Note that use of this macro likely invokes undefined behavior: The resulting pointer is not guaranteed to be properly aligned, and if the data was written as some other type than an int variant, it's a violation of strict aliasing rules as well.
Also, the choice of int to do the pointer arithmetic is a very poor choice, the calculation should at least be done via size_t or uintptr_t to guarantee that the pointer is not truncated during the cast to the integer type. My rewritten version does not have this specific problem, however, the danger of undefined behavior remains with both versions.
Finally, as Olaf rightly noted in the comments, it's also a bad idea to cast to volatile unsigned* since the width of this type is implementation defined. A cast to volatile uint32_t* would likely be more appropriate for communication with hardware.

Related

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?

Type casting pointer dereference

Sorting through a retired engineers code and I encountered a fairly simple macro, but my C knowledge isn't great.
#define mem32(addr) (*(unsigned long volatile *)(addr))
Am I correctly calling this a type casting pointer dereference?
It types casts addr and then derefences it? Or the other way around? Does it matter?
Does order matter for type qualifiers and type specifiers? I had assumed (before this) type qualifiers had to precede type specifiers, but that must not be the case
Syntax question. What's the purpose of the 2nd * ?
Am I correctly calling this a type casting pointer dereference?
Yes.
It types casts addr and then derefences it? Or the other way around? Does it matter?
The *(unsigned long volatile *)(addr) is typecasting addr and then dereferencing it.
Does order matter for type qualifiers and type specifiers?
No. Order doesn't matter. C11 section §6.7.2/2
[...] the type specifiers may occur in any order, possibly
intermixed with the other declaration specifiers. [...]
The cast (unsigned long volatile *)(addr) happens before the dereferencing.
And no, the order of the words unsigned, long, and volatile does not matter as long as no further operators are mixed in. I. e. volatile int* and int volatile* are the same, but int * volatile is something different.
On a high level, the purpose of this macro is to take any pointer, and read the first four bytes from that memory address.
However, this invokes undefined behavior if the pointer that's passed to mem32 is neither a pointer to long or char! This is due to strict aliasing rules. Older compilers used to safely generate the intended code for this macro, but modern compilers may just optimize the code using that macro away if they prove a type mismatch. So, don't use this in new code.

Fixed-sized pointer type in C99

I want to create a type to store pointers. The type should be compatible with C99 and have a fixed-width of 64 bits. I came up with several alternatives but they all seem flawed:
Using uint64_t is incorrect since conversions between pointers and integers are implementation-defined [C99 standard, 6.3.2.3].
uinptr_t also appears to be out of the picture, since the width of this type is not fixed and the type is optional anyway [7.18.1.4].
Using a struct such as
struct {
#ifdef __LP64__
void* ptr;
#else
// if big endian the following two fields need to be flipped
void* ptr;
uint32_t padding;
#endif
} fixed_ptr_type;
does not work either because the size of a pointer is not fixed even within the same implementation
Is there any C99-compatible definition of the type I'm looking for?
Object pointers
The best type to store object pointers is void *. Any object pointer can be converted to void * and back again.
Function pointers
A void * cannot necessarily store a function pointer. However, any function pointer can be converted to another type of function pointer, so you could store them in some arbitrary type (such as void (*)(void)).
Padding
I have no idea why you would need your pointer type to have a predetermined size, but you could pad them by using a union and hope that the result is not too large:
union fixed_ptr_type {
void *p;
char c[64/CHAR_BIT];
};
assert (CHAR_BIT * sizeof (union fixed_ptr_type) == 64);
I don't understand your objection to using the void * with padding. All objects of the same type have the same size. If a different object pointer type has a different size, that doesn't matter, because you convert it to void * to store it in your super-pointer.
Regarding uintptr_t: If it is not supported , then chances are that it's because there is actually no way of doing this on the particular platform.
So you could use uintptr_t. To add in the fixed-width requirement, you could cast to uintptr_t then to uint64_t (if you're happy with knowing you'll have to change your code when someone puts out a system that has pointers greater than 64bits!)
You cannot portably store pointer values in a 64-bit type. It's perfectly legal for an implementation to use 128-bit pointers.
If you don't mind losing portability to systems with pointers bigger than 64 bits, you can probably get away with using uint64_t. Conversions from pointer types to uint64_t are not guaranteed to work correctly without losing information, but they will almost certainly do so on any reasonable systems where pointers are no wider than 64 bits.
If an implementation has no 64-bit unsigned integer type without padding bits, then it will not define uint64_t at all (for example, a system with 9-bit bytes would not be able to implement uint64_t). There's a type uint_least64_t that's guaranteed, as the name implies, to be at least 64 bits wide; it will be exactly 64 bits on most systems, and wider than 64 bits only on systems where uint64_t doesn't exist.
uintptr_t is guaranteed to hold a converted void* value without loss of information, but it's not guaranteed to exist -- and if it doesn't exist, then no integer type can hold a converted void* value without loss of information. A conforming implementation needn't necessarily have any integer type that can hold a pointer value without loss of information.
Function pointers are another matter. Conversion from a function pointer to void*, or to any integer type, has undefined behavior (because the standard doesn't say what the behavior should be).
There simply is no 100% portable way to do what you're trying to do. You'll just have to settle for 99.9% portability. If you're not concerned with function pointers, I'd suggest using uint64_t (perhaps defining your own typedef to make it clear what you're doing) and add a compile-time or run-time check to confirm that sizeof (void*) <= sizeof (uint64_t). That should cover every existing implementation that I've ever heard of.
It might be helpful to know what your actual goal is. Why do you want to store pointers in no more or less than 64 bits? What problem does this solve that storing them in void* objects doesn't solve?
Incidentally, the __LP64__ macro that you mention in your question is non-standard.

what does the following type casting do in C?

I have a question about type casting in C:
void *buffer;
(int *)((int)buffer);
what is this type casting doing? and what does the ((int)buffer) doing?
Imagine you are on a Linux/x86-64 computer like mine. Then pointers are 64 bits and int is 32 bits wide.
So, the buffer variable has been initialized to some location; Perhaps 0x7fff4ec52020 (which could be the address of some local variable, perhaps inside main).
The cast (int)buffer gives you an int, probably the least significant 32 bits, i.e. 0x4ec52020
You are casting again with (int*)((int)buffer), which gives you the bogus address 0x000000004ec52020 which does not point into valid memory. If you dereference that bogus pointer, you'll very probably get a SIGSEGV.
So on some machines (notably mine) (int *)((int)buffer) is not the same as (int*)buffer;
Fortunately, as a statement, (int *)((int)buffer); has no visible side effect and will be optimized (by "removing" it) by the compiler (if you ask it to optimize).
So such code is a huge mistake (could become an undefined behavior, e.g. if you dereference that pointer). If the original coder really intended the weird semantics described here, he should add a comment (and such code is unportable)!
Perhaps #include-ing <stdint.h> and using intptr_t or uintptr_t could make more sense.
Let's see what the C Standard has to say. On page 55 of the last freely published version of the C11 standard http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf we have
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.
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.
What does this mean in your example? Section 6 says that the cast (int)buffer will compile, but if the integer is not big enough to hold the pointer (which is likely on 64-bit machines), the result is undefined. The final (int*) casts back to a pointer.
Section 5 says that if the integer was big enough to hold the intermediate result, the result is exactly the same as just casting to (int*) from the outset.
In short the cast (int) is at best useless and at worst causes the pointer value to be lost.
In straight C code this is pointless because conversions to and from void* are implicit. The following would compile just fine
int* p = buffer;
Worse though is this code potentially introduces errors. Consider the case of a 64 bit platform. The conversion to int will truncate the pointer to 32 bits and then assign it to an int*. This will cause the pointer value to be truncated and certainly lead to errors.

Dealing with pointer argument in C

I'm using a library which has a function with the following signature:
void LED_stop_blink_task ( void * callback_parameter );
The actual parameter the void pointer stands for is a pointer to uint32_t, which is the number of the led on the board.
Is there a way to call this function without using a variable to hold the data ?
In my imagination it will be like
LED_stop_blink_task(&35);
or the only way is like this:
uint32_t led_num = 35;
LED_stop_blink_task(&led_num);
If you're asking why I want to throw the variable away, well, I'm just curious if it's possible...
On most platforms it's possible to simply stuff the int in a void *:
LED_stop_blink_task((void *)32);
Then in the function you can cast to int.
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.
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.
In practice this will work on any POSIX-supported platform. For example TLPI says:
Strictly speaking, the C standards don’t define the results of casting
int to void * and vice versa. However, most C compilers permit these
operations, and they produce the desired result; that is, int j ==
(int) ((void *) j).
Cnicutar's answer is almost perfect; let me extend it with that it's not really portable - int is not guaranteed to be of the same size (or smaller) than a pointer, so you should use intptr_t or uintptr_t instead.

Resources