I have the following C function used in an embedded software project. It's also used for the verification of the hardware and not in production.
void reg_read(int addr) {
int result;
int* reg_addr = (int*)(addr); // I cast the value of the addr variable to the reg_addr pointer hoping that it would point to the address stored in addr
result = (*reg_addr); // this should trigger a read transaction on the AXI interface of the ARM CPU that I'm simulating
}
// later on...in the main function
reg_read(0x08000704);
The embedded software runs in a simulated environment(using QEMU+SystemC) and I can see if the AXI read transaction happens or not. In this case it doesn't happen.
However, if I assign a constant value to the pointer like int* reg_addr = (int*)0x08000704; then the AXI transaction happens.
I assume the compiler generates different instructions in each case. I also tried to declare reg_addr as volatile int* reg_addr; but it didn't work either.
Is there a portable and compliant way of casting the value of an int variable to an int pointer?
Your question is:
Is there a portable and compliant way of casting the value of an int
variable to an int pointer?
There is not. Summed up from the comments:
Conversion of an integer to a pointer is implementation defined - Antti Haapala
It was suggested that you use uintptr_t or similar which is a good suggestion from Eugene Sh.
In the example of uintptr_t
uintptr_t = unsigned integer type capable of holding a pointer
From the vadefs.h file from the Microsoft Visual C++ header file vadefs.h it is defined as:
#ifdef _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef unsigned int uintptr_t;
#endif
In this manner, if you compile for x86 it would resolve to a 32bit data type and for x64, a 64 bit data type.
Related
I've inherited some old code that assumes that an int can store values from -231 to 2^31-1, that overflow just wraps around, and that the sign bit is the high-order bit. In other words, that code should have used uint32_t, except that it wasn't. I would like to fix this code to use uint32_t.
The difficulty is that the code is distributed as source code and I'm not allowed to change the external interface. I have a function that works on an array of int. What it does internally is its own business, but int is exposed in the interface. In a nutshell, the interface is:
struct data {
int a[10];
};
void frobnicate(struct data *param);
I'd like to change int a[10] to uint32_t a[10], but I'm not allowed to modify the definition of struct data.
I can make the code work on uint32_t or unsigned internally:
struct internal_data {
unsigned a[10];
};
void frobnicate(struct data *param) {
struct internal_data *internal = (struct internal_data *)param;
// ... work with internal ...
}
However this is not actually correct C since it's casting between pointers to different types.
Is there a way I can add compile-time guards so that, for the rare people for whom int isn't “old-school” 32-bit, the code doesn't build? If int is less than 32 bits, the code has never worked anyway. For the vast majority of users, the code should build, and in a way that tells the compiler not to do “weird” things with overflowing int calculations.
I distribute the source code and people may use it with whatever compiler they choose, so compiler-specific tricks are not relevant.
I'm at least going to add
#if INT_MIN + 1 != -0x7fffffff
#error "This code only works with 32-bit two's complement int"
#endif
With this guard, what can go wrong with the cast above? Is there a reliable way of manipulating the int array as if its elements were unsigned, without copying the array?
In summary:
I can't change the function prototype. It references an array of int.
The code should manipulate the array (not a copy of the array) as an array of unsigned.
The code should build on platforms where it worked before (at least with sufficiently friendly compilers) and should not build on platforms where it can't work.
I have no control over which compiler is used and with which settings.
However this is not actually correct C since it's casting between pointers to different types.
Indeed, you cannot do such casts, because the two structure types are not compatible. You could however use a work-around such as this:
typedef union
{
struct data;
uint32_t array[10];
} internal_t;
...
void frobnicate(struct data *param) {
internal_t* internal = (internal_t*)param;
...
Another option if you can change the original struct declaration but not its member names, is to use C11 anonymous union:
struct data {
union {
int a[10];
uint32_t u32[10];
}
};
This means that user code accessing foo.a won't break. But you'd need C11 or newer.
Alternatively, you could use a uint32_t* to access the int[10] directly. This is also well-defined, since uint32_t in this case is the unsigned equivalent of the effective type int.
Is there a way I can add compile-time guards so that, for the rare people for whom int isn't “old-school” 32-bit, the code doesn't build?
The obvious is static_assert(sizeof(int) == 4, "int is not 32 bits"); but again this requires C11. If backwards compatibility with older C is needed, you can invent some dirty "poor man's static assert":
#define stat_assert(expr) typedef int dummy_t [expr];
#if INT_MIN != -0x80000000
Depending on how picky you are, this isn't 100% portable. int could in theory be 64 bits, but probably portability to such fictional systems isn't desired either.
If you don't want to drag limits.h around, you could also write the macro as
#if (unsigned int)-1 != 0xFFFFFFFF
It's a better macro regardless, since it doesn't have any hidden implicit promotion gems - note that -0x80000000 is always 100% equivalent to 0x80000000 on a 32 bit system.
I was going through a programming manual for one of the microcontrollers I came across and it had the preprocessor definition as follows:
#define SCICTL1A (volatile unsigned int *)0x7051
and a statement in the source file as follows:
*SCICTL1A = 0X0003;
My question is, what is the pointer variable here and what is it pointing to, (I have never come across pointer definitions in preprocessor directives before since I am a beginner to C programming) and what does the assignment statement do?
There is no variables here. The macro expands as text in place, so the 2nd excerpt becomes
*(volatile unsigned int *)0x7051 = 0X0003;
It casts the unsigned integer 0x7051 into a pointer to volatile unsigned integer, then references this in assignment. Essentially it stores 0x0003 into the unsigned integer-wide piece of memory that starts from address 0x7051 (or, however the integer-to-pointer conversion happens to work on your target platform)
volatile is required so that the compiler does not just optimize the assignment out - it must be strictly evaluated and considered a side effect (see as-if rule).
As for the actual reason why this is done - it is probably some memory-mapped device, check the microcontroller datasheets for more information.
There is no variable there. Only the pointer.
the *SCICTL1A = 0X0003; is replaced by the preprocessor by the:
*(volatile unsigned int *)0x7051 = 0x0003;
You just write the location with the address of the 0x07051. That does it mean depends on your implementation
I'm assuming you're using a TMS320F2803x Piccolo microcontroller: http://www.ti.com/lit/ds/sprs584l/sprs584l.pdf
According to this document, address 0x7051 is Control Register 1 for the Serial Communications Interface (SCI) Module.
According to this document, https://www.swarthmore.edu/NatSci/echeeve1/Ref/embedRes/DL/28069TechRefManual_spruh18d.pdf, you're able to do the following with this register:
SCICTL1 controls the receiver/transmitter enable, TXWAKE and SLEEP
functions, and the SCI software reset.
I have a function foo(void* pBuf). I need to pass it a 64 bit address but I can't seem to get the right typecast when I'm passing by value.
Example: foo(address). Where- uint64_t address=0x00000000DEADBEEF
EDIT: Compiling using an ARM compiler.
uint64_t foo(void *pBuf){
uint64_t retAddr = (uint64_t) pBuf;
retAddr += 0x100000;
return retAddr;
}
I'm on a 32-bit ARM and sizeof(void *) is 4
Clarification: Why I needed a 64-bit address on a 32-bit ARM?
Because my memory map uses 36-bit addressing.
Call it this way:
uint64_t address = 0xDEADBEEF;
foo((void*)address);
That is, you cast the address to a void-pointer to be compatible with the function signature.
Sorry to necro this question, but none of these answers seem reasonable to me. This is a fairly straightforward type conversion problem. It seems as though people were caught up on 64-bit addressing on a 32-bit system, when this could easily be for a peripheral or some other address space besides the system itself.
In the OP's case, a cast directly to uint64_t would cause undefined behavior because of the additional four bytes that do not exist in void *. In the case of the M4 calling convention, p would typically be passed in a single register, likely r0. There are no additional upper bytes for uint64_t to alias, so your compiler is rightly issuing a warning for this.
Under the GCC 7.3 arm-none-eabi port, void * can be safely cast to size_t (aka unsigned int) because they both have size and alignment of 4. Once that is done, you can safely promote unsigned int to uint64_t (aka unsigned long long int) by assignment. The promotion is better defined behavior than a cast.
uint64_t foo(void *p){
uint64_t a = (size_t) p;
a += 0x100000;
return a;
}
You should not use a 64-bits type for an address, as it is undefined behavior for 32-bits (or any non-64 bits) systems.
Rather, prefer using uintptr_t, which is standard C.
See this question for more details or this page for references.
Then a solution could be :
uintptr_t address = 0xDEADBEEF; /* will trigger a warning if the constant is > max possible memory size */
foo((void*)address);
Note : if uintptr_t is not available on your system, size_t is usually a good second choice.
Part 2 :
Looks like, in your rephrased question, you want to convert an address into a 64-bits integer.
In which case, a direct cast from ptr to integer is likely to trigger a compiler warning, due to potential differences in wideness.
Prefer a double cast :
uint64_t value = (uint64_t)(size_t) ptr;
I can think of two ways to get this right. Got a solution to my problem by calling foo the first way
foo((void*)(uint32_t)address)
This works only because my input to foo is always a 32-bit value. The returned value can be 64-bit.
Of course, a proper fix would be to change foo itself, if I could modify it.
I could just pass foo(&address). Inside foo, retAddr = *pBuf.
Thanks for all the suggestions!
I am getting error
error: aggregate value used where an integer was expected
on compiling this code:
#include <stdio.h>
typedef unsigned long U32;
typedef struct hello_s
{
U32 a:8;
U32 b:24;
}hello_t;
int main()
{
hello_t str;
U32 var;
str.a = 0xAA;
str.b = 0xAAA;
var = (U32)str;
printf("var : %lX\n", var);
return 0;
}
Can someone please explain what the error means, and what I am doing wrong.
EDIT: I understand this is a stupid thing to do. What I wanted to know was why the compiler is crying about this. Why cant it just assign the first 32 bits to the integer.
var = (U32)str;
Because str is an object of a structure type and you cannot convert structure objects to object of arithmetic types. C does not let you perform this kind of conversion.
If you want to access you structure object as an integer you can create an union of your structure and of an U32.
Note that the common construct var = *(U32 *) str; is undefined behavior in C. It violates aliasing and alignment rules.
Well, I think one should not mistake the C99 spec by assuming that it is against the language standards.
The standard only says that the results of the conversion may not portable across different machines/architectures.
As long as you have coded the program to work on a particular architecture, it's fine.
For example I group selective members of a data structure DataStr_t that uniquely identifies the object (i.e., the key), packed into another struct, say, DataStrKey_t. I'll make sure that sizeof(DataStrKey_t) is equal to sizeof(uint64) and for all practical purposes use it as uint64 as it is easy to handle.
I also do the below operation often:
memcmp(&var_uint64, &var_DataStructKey, sizeof(uint64));
If you read access or write access the object using the key on a machine the value resulting from conversion is predictable and consistent in bit-wise alignment.
Well if you move "only this data" to a different machine (which actually didn't write the data) and try to read it, things may break.
Your program slightly modified for more explanation and successful compilation:
Here, as long as LINE_A and LINE_B are execute on the same machine result is always predictable.
But if you write the (var_uint64,var_DataStructKey) to a file and read it from a different machine, then execute LINE_B on those populated values, comparison "may" fail.
#include <stdio.h>
#include <string.h>
typedef unsigned long U32;
typedef struct hello_s
{
U32 a:8;
U32 b:24;
}hello_t;
int main()
{
hello_t str;
U32 var;
str.a = 0xAA;
str.b = 0xAAA;
var = *(U32 *)(&str); //LINE_A
if(0 == memcmp(&var, &str, sizeof(U32))) //LINE_B
printf("var : %lu\n", var);
return 0;
}
I guess my answer is too late, but attempted to explain.
And what do you expect that cast to result in exactly? You could always just cast it's address to a pointer to int and dereference it... but are you sure you can safely do so (no, you can't)? Is structure member alignment going to bite you someday (the answer is "probably, yes, it depends")?
Also, from the C99 styandard:
C99 §6.7.2.1, paragraph 10: "The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined."
That is not always a stupid thing to do. In my case, I have a struct that I need to send over a network connection. The data must be sent over an SPI bus in byte form, so the struct must be accessed a byte at a time. I used this define to access each byte. You must be aware of the byte ordering of your platform to do this correctly. Also, you must make sure your structs are __PACKED (see also: C/C++: Force Bit Field Order and Alignment), so the compiler does not insert any padding blocks or alignment blocks. This will also not work if any of the bit members fall across the byte boundaries (at least, with the Microchip XC16 compiler it does not).
typedef unsigned char byte;
#define STRUCT_LB(x) ((byte *)(&x))[0]
#define STRUCT_HB(x) ((byte *)(&x))[1]
A nicer way to do this is to define your struct as a union of a bitfield and a byte array like so:
typedef unsigned char byte;
typedef struct {
union {
struct __PACKED {
byte array[2];
} bytes;
struct __PACKED {
byte b0: 1;
byte b1: 1;
byte b2: 1;
byte b3: 1;
byte b4: 1;
byte other: 3;
byte more: 6;
byte stuff: 2;
} fields;
};
} MyData;
Not all typecasting are allowed in C. Per this manual, only the following cases are legal,
Convert an integer to any pointer type.
Convert a pointer to any integer type.
Convert a pointer to an object to a pointer to another object.
Convert a pointer to a function to a pointer to another function.
Correctness of converting null between pointers (either object or function).
Hence, casting a struct to an integer is obviously not a legal conversion.
First off, this is not a dupe of:
Is it safe to cast an int to void pointer and back to int again?
The difference in the questions is this: I'm only using the void* to store the int, but I never actually use it as a void*.
So the question really comes down to this:
Is a void * guaranteed to be at least as wide as an int
I can't use intptr_t because I'm using c89 / ANSI C.
EDIT
In stdint.h from C99 ( gcc version ) I see the following:
/* Types for `void *' pointers. */
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned long int uintptr_t;
#else
# ifndef __intptr_t_defined
typedef int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned int uintptr_t;
#endif
Could I possibly just jerry rig something similar and expect it to work? It would seem that the casting should work as all intptr_t is is a typedef to an integral type...
No, this is not guaranteed to be safe.
The C99 standard has this to say (section 6.3.2.3):
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.
I'm pretty confident that pre-C99 won't be any different.
FreeRTOS stores timer IDs in Timer_t as void* pvTimerID. So when using this as a storage space, and NOT a pointer to something, it is necessary to cast it to something that can be used as an array index, for instance.
so to read the id, stored as a void*:
void* pvId = pxTimer->pvTimerID;
int index = (int)(pvId - NULL);
There is a C FAQ: Can I temporarily stuff an integer into a pointer, or vice versa? .
The cleanest answer is: no, this is not safe, avoid it and get on with it. But POSIX requires this to be possible. So it is safe on POSIX-compliant systems.
Here's a portable alternative.
static const char dummy[MAX_VALUE_NEEDED];
void *p = (void *)(dummy+i); /* cast to remove the const qualifier */
int i = p-dummy;
Of course it can waste prohibitively large amounts of virtual address space if you need large values, but if you just want to pass small integers, it's a 100% portable and clean way to store integer values in void *.