#define NUMOFDMABUF 20
u8 *data[NUMOFDMABUF];
int main()
{
for (u32 i = 0; i < NUMOFDMABUF; i++)
{
data[i] = (void *)(RX_BUFFER_BASE + (i * MAX_PKT_LEN)); //-Wint-to-pointer-cast
}
}
This is for bare metal application and i want to explicitly set memory addresses of ram locations to an array of pointers. The code works, but how do i write the code to avoid the occurrence of this warning?
If i explicitly set the address as a value, no issues... but when i do it this way it throws the the warning. I am brain farting, so thoughts appreciated :)
The text of the warning produced by gcc is more descriptive.
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
The OP mentions in the comments how RX_BUFFER_BASE is defined:
#define RX_BUFFER_BASE 0x40000000
That macro is later textually expanded in the line
data[i] = (void *)(RX_BUFFER_BASE + (i * MAX_PKT_LEN));
The type of i is a non standard U32, I'll assume it to be a 32-bit unsigned integer. MAX_PKT_LEN is undisclosed, but I'll assume it to be defined as RX_BUFFER_BASE.
Now, the type of an integer constant is the first type in which the value can fit1, so 0x40000000 could be an unsigned int or an unsigned long int depending on the implementation, or if we consider fixed width types, an uint32_t, but not an uint64_t.
Using an integer suffix, like 0x40000000ull, would have forced it to be an unsigned long long.
We can assume2 that the other variables in that expression have the same type, while pointers, in OP's implementation, have a wider representation. Therefore the warning.
The asker could have used a type specifically designed for this kind of pointer arithmetic, like uintptr_t, which is an unsigned integer type capable of holding a pointer to void:
#include <stdint.h>
const uintptr_t buffer_base = 0x40000000;
1) C17 standard (ISO/IEC 9899:2018): 6.4.4.1 Integer constants (p: 45-46) or see e.g. https://en.cppreference.com/w/c/language/integer_constant#The_type_of_the_integer_constant
2) Sorry, that's a lot assumptions, I know, but it's not entirely my fault.
how do i write the code to avoid the occurrence of this warning?
This may-or-may-not work in all environments.
It is just a proposal that may work for this OP.
I haven't done "bare metal" stuff to any serious degree.
But this compiles on my old computer without warnings...
int main() {
uint8_t *d[20];
memset( d, 0, sizeof d ); // start clean
for( uint32_t i = 0; i < sizeof d/sizeof d[0]; i++ )
d[i] += 0x2468 + ( i * 256 ); // NB "+="
return 0;
}
I'm not going to go anywhere near dereferencing any of those pointers though.
Related
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'm writing some code that maps virtual addresses to physical addresses.
I have code along these lines:
if (address > 0xFFFF)
Status = XST_FAILURE; // Out of range
else if (address <= 0xCFFF || address >= 0xD400) {
// Write to OCM
Xil_Out8(OCM_HIGH64_BASEADDR + OCM_OFFSET + address, data);
else { // (address >= 0xD000)
// Write to external CCA
Status = ext_mem_write(address, data);
I get a compiler warning:
comparison between pointer and integer [enabled by default]
I realize that I'm comparing two different types (pointer and integer), but is this an issue? After all, comparing a pointer to an integer is exactly what I want to do.
Would it be cleaner to define pointer constants to compare to instead of integers?
const int *UPPER_LIMIT = 0xFFFF;
...
if (address > UPPER_LIMIT ){
....
The clean way is to use contants of type uintptr_t, which is defined to be an unsigned integer that can uniquely map between pointers and integers.
This should be defined by #include <stdint.h>. If it is not defined then it indicates that either your compiler doesn't follow the C standard, or the system does not have a flat memory model.
It's intended to be mapped in the "obvious" way , i.e. one integer per byte in ascending order. The standard doesn't absolutely guarantee that but as a quality of implementation issue it's hard to see anything else happening.
Example:
uintptr_t foo = 0xFFFF;
void test(char *ptr)
{
if ( (uintptr_t)ptr < foo )
// do something...
}
This is well-defined by the C standard. The version where you use void * instead of uintptr_t is undefined behaviour, although it may appear to work if your compiler isn't too aggressive.
That's probably why Linux Kernel uses unsigned long for addresses (note the difference -- pointer points to an object, while address is an abstract code representing location in memory).
That's how it seem from compiler perspective:
C standard doesn't define how to compare int (arithmetic type) literal 0xFFFF and pointer address -- see paragraph 6.5.8
So, it has to convert operands somehow. Both conversions are implementation defined as paragraph 6.3.2.3 states. Here are couple of crazy decisions that compiler eligible to make:
Because 0xFFFF is probably int -- see 6.4.4, it may coerce pointer to int and if sizeof(int) < sizeof(void*), you will lose higher bytes.
I can imagine more crazier situations when 0xFFFF is sign extended to 0xFFFFFFFF (shouldn't be, but why not)
Of course, none of (2) should happen, modern compilers are smart enough. But it can happen (I assume you're writing something embedded, where it is more likely to happen), so that's why compiler raises a warning.
Here is one practical example of "crazy compiler things": in GCC 4.8 optimizer started to treat integer overflow as UB (Undefined Behavior) and omit instructions assuming programmer doesn't want integer overflow: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61569
I'm referring to N1570 - C11 standard draft
Cast pointer to unsigned int to avoid warnings: (unsigned)address - in case of 32 or 16 bit address space.
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 *.
Here's a random problem in C black magic I just came up with:
Write a function that returns 1 if malloc has been prototyped to return a pointer type and 0 if malloc has a return type of int (either implicitly or due to wrong prototype), without invoking any implementation-defined or undefined behavior.
I believe it's solvable, but I haven't worked out the solution. Note that calling the function cannot be necessary and in fact is not possible since calling a function with the incorrect prototype is undefined behavior. I have some ideas for ingredients but I think it makes for a better puzzle (and possibly more diverse ideas) if I leave them out for now.
I don't need the solution for any immediate use, but it could be handy in configure scripts and such.
Update: A better example of the usefulness (with strdup instead of malloc):
#undef strdup
#define strdup(x) (strdup_has_proto ? strdup((x)) : my_strdup((x)))
i.e. being able to implement X_has_proto as an expression at the source level could be a portable way to use functions which a system might or might not have, and fall back on a local replacement, without needing any separate configure step.
There is no solution given the assumptions. What you need is a function whose body has free variables that represent the intermediate type information in the compiler that isn't ever lowered into the target language except in implementation-defined ways, e.g. debugger information. Relax the requirements so that you allow certain prescribed kinds of implementation-defined behavior, and you might find a solution.
Since void * and int can be added I was thinking of other operators to try, such as comparison. The results, especially with R's ?: trick are oddly inconsistent:
int f() { return 0; }
void *g() { return 0; }
#define T(x) (1?0:x()) /* R's trick from a comment */
void h()
{
void *n = 0;
int i = 0;
f() > n; /* m.c:12: warning: comparison between pointer and integer */
g() > n;
T(f) > n;
T(g) > n;
f() > i;
g() > i; /* m.c:18: warning: comparison between pointer and integer */
T(f) > i;
T(g) > i; /* m.c:20: warning: comparison between pointer and integer */
}
Some partial answers and answers to related questions:
If the function in question is supposed to return a floating point type, the test is easy:
#define HAS_PROTO_FP_RET_1_ARG(f) !!((1?1:(f)(0))/2)
The 1 gets promoted to a floating point type if and only if f is declared to return a floating point type, and division by 2 results in a nonzero value if and only if 1 has floating point type.
This test could be useful for checking for the presence of C99 math functions.
With pointers, the expression (1?0:(f)(0)) is potentially useful - it evaluates to either 0 (an int) or (void *)0) (a null pointer constant) depending on the return type of f. But I have yet to find any devious way to test whether an expression has integer or pointer type.
The big problem I'm running into is that void * cannot participate in pointer arithmetic and does not implicitly convert to other pointer types in arithmetic contexts. For example, if it did, this would work (slightly breaking my rules about UB/IDB too):
#define HAS_PROTO_PTR_RET_1_ARG(f) ((int)((char (*)[2])2 - (1?0:(f)(0))) == 1)
Any ideas for getting around this problem?
Update: I have a solution that depends on nothing more than intmax_t being larger than int:
#define HAS_PROTO_PTR_RET_1_ARG(f) ( \
sizeof(int)!=sizeof(void *) ? sizeof ((f)(0)) == sizeof(void *) : \
sizeof (1?(intmax_t)0:(f)(0)) == sizeof(void *) )
There are two cases. If int and void * have different sizes, we simply check the size of the return value. Otherwise, int and void * are the same size, so (by the big assumption) intmax_t and void * are not the same size. We construct an expression whose type is intmax_t if the return type is int, and void * if the return type is void *, and test its size.
This macro fails only on machines where int, intmax_t, and void * all have the same size. Practically speaking, that means only on DSPs with 64-bit or larger int. Since pretty much all real POSIX and POSIX-like systems have fixed-size 32-bit int and intmax_t is required to be at least 64-bit, this is portable enough to make me happy.
How about some gloriously bad hacks?
char has_malloc = 0;
#define malloc(x) \
has_malloc = 1; \
malloc((x))
//.. run includes here
#undef malloc
But then, you could just #include <malloc.h> for the guarantee.
Edit:
Why not just define an int malloc()? If anyone tries to call an int malloc, it should call your version instead.
Is there an integer type with the same size as pointer? Guaranteed on all microarchitectures?
According to this Wikipedia page, in C99 your stdint.h header might declare intptr_t and uintptr_t, but then that of course requires
C99
A compiler implementor which has chosen to implement this optional part of the standard
So in general I think this one is tough.
Simply put, no. Not guaranteed on all architectures.
My question is: why? If you want to allocate a type big enough to store a void*, the best thing to allocate is (surprisingly enough :-) a void*. Why is there a need to fit it within an int?
EDIT: Based on your comments to your duplicate question, you want to store special values of the pointer (1,2,3) to indicate extra information.
NO!! Don't do this!!. There is no guarantee that 1, 2 and 3 aren't perfectly valid pointers. That may be the case in systems where you're required to align pointers on 4-byte boundaries but, since you asked about all architectures, I'm assuming you have portability as a high value.
Find another way to do it that's correct. For example, use the union (syntax from memory, may be wrong):
typedef struct {
int isPointer;
union {
int intVal;
void *ptrVal;
}
} myType;
Then you can use the isPointer 'boolean' to decide if you should treat the union as an integer or pointer.
EDIT:
If execution speed is of prime importance, then the typedef solution is the way to go. Basically, you'll have to define the integer you want for each platform you want to run on. You can do this with conditional compilation. I would also add in a runtime check to ensure you've compiled for each platform correctly thus (I'm defining it in the source but you would pass that as a compiler flag, like "cc -DPTRINT_INT"):
#include <stdio.h>
#define PTRINT_SHORT
#ifdef PTRINT_SHORT
typedef short ptrint;
#endif
#ifdef PTRINT_INT
typedef int ptrint;
#endif
#ifdef PTRINT_LONG
typedef long ptrint;
#endif
#ifdef PTRINT_LONGLONG
typedef long long ptrint;
#endif
int main(void) {
if (sizeof(ptrint) != sizeof(void*)) {
printf ("ERROR: ptrint doesn't match void* for this platform.\n");
printf (" sizeof(void* ) = %d\n", sizeof(void*));
printf (" sizeof(ptrint ) = %d\n", sizeof(ptrint));
printf (" =================\n");
printf (" sizeof(void* ) = %d\n", sizeof(void*));
printf (" sizeof(short ) = %d\n", sizeof(short));
printf (" sizeof(int ) = %d\n", sizeof(int));
printf (" sizeof(long ) = %d\n", sizeof(long));
printf (" sizeof(long long) = %d\n", sizeof(long long));
return 1;
}
/* rest of your code here */
return 0;
}
On my system (Ubuntu 8.04, 32-bit), I get:
ERROR: ptrint typedef doesn't match void* for this platform.
sizeof(void* ) = 4
sizeof(ptrint ) = 2
=================
sizeof(short ) = 2
sizeof(int ) = 4
sizeof(long ) = 4
sizeof(long long) = 8
In that case, I'd know I needed to compile with PTRINT_INT (or long). There may be a way of catching this at compile time with #if, but I couldn't be bothered researching it at the moment. If you strike a platform where there's no integer type sufficient for holding a pointer, you're out of luck.
Keep in mind that using special pointer values (1,2,3) to represent integers may also not work on all platforms - this may actually be valid memory addresses for pointers.
Still ,if you're going to ignore my advice, there's not much I can do to stop you. It's your code after all :-). One possibility is to check all your return values from malloc and, if you get 1, 2 or 3, just malloc again (i.e., have a mymalloc() which does this automatically). This'll be a minor memory leak but it'll guarantee no clashes between your special pointers and real pointers.
The C99 standard defines standard int types:
7.18.1.4 Integer types capable of holding object pointers
The following type designates a signed 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:
intptr_t
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:
uintptr_t
These types are optional.
C99 also defines size_t and ptrdiff_t:
The types are
ptrdiff_t
which is the signed integer type of the result of subtracting two pointers;
size_t
which is the unsigned integer type of the result of the sizeof operator; and
The architectures I've seen have the maximum size of an object equal to the whole memory, so sizeof(size_t) == sizeof(void*), but I'm not aware of anything that is both portable to C89 ( which size_t is ) and guaranteed to be large enough ( which uintptr_t is ).
This would be true on a standard 32 bit system, but there certainly are no guarantees, and you could find lots of architectures where it isn't true. For example, a common misconception is that sizeof(int) on x86_64 would be 8 (since it's a 64 bit system, I guess), which it isn't. On x86_64, sizeof(int) is still 4, but sizeof(void*) is 8.
The standard solution to this problem is to write a small program which checks the sizes of all int types (short int, int, long int) and compares them to void*. If there is a match, it emits a piece of code which defines the intptr type. You can put this in a header file and use the new type.
It's simple to include this code in the build process (using make, for example)
No, the closest you will come to a portable pointer-capable integer type would be intptr_t and ptrdiff_t.
No.
I do not believe the C standard even specifies standard int sizes. Combine that with all the architectures out there (8/16/32/64bit etc) and there is no way to guarantee anything.
int data type would be the answer on most architectures.
But thre is NO guarantee to this for ANY (micro)architecture.
The answer seems to be "no", but if all you need is a type that can act as both, you can use a union:
union int_ptr_t {
int i;
void* p;
};
Usually sizeof(*void) depends on memory bus width (although not necessarily - pre-RISC AS/400 had 48-bit address bus but 64-bit pointers), and int usually is as big as CPU's general-purpose register (there are also exceptions - SGI C used 32-bit ints on 64-bit MIPS).
So there is no guarantee.