do you know what does this code mean?
#define StartEsub (unsigned short (**) (unsigned short \
AnalogConfigReg, \
unsigned short \
AnalogClockMask)) 0x00502501
Get rid of the messy macro and you get
(unsigned short (**) (unsigned short AnalogConfigReg,
unsigned short AnalogClockMask)) 0x00502501
Which is a cast from an integer, representing an address, into a pointer to a function pointer. How a pointer to a function pointer is meaningful for your specific case, I have no idea.
A much better and more readable way to write the same would be:
typedef unsigned short func_t (unsigned short AnalogConfigReg,
unsigned short AnalogClockMask);
(func_t**) 0x00502501
It seems to be defining a hard-coded vector address for a function (a pointer to a function pointer). It will be specific to your particular embedded target, so you might want to add details about the system where this code is being used.
In more detail - there is apparently a function somewhere that looks like this:
unsigned short foo (unsigned short AnalogConfigReg,
unsigned short AnalogClockMask)
and a pointer to this function is stored at the address 0x00502501.
This kind of thing is sometimes known as a "hook", and it probably allows a user-defined function to be installed by modifying this hook address.
Related
I want to use the method strtoull(...) but do I really have to type out unsigned long long whenever I use it?
The largest integer typedef I could find was uint64_t / size_t but it is not the same as unsigned long long.
I believe unsigned long long takes up to much space. Is there some sort of official and recognized shortcut for it among the community?
Do I have to make my own type? What would be a good name for it? u128int_t or uLLong?
You say you "need a type for unsigned long long int", but unsigned long long int is a type.
Apparently your concern is that the name unsigned long long int is too long to type. You have a point, but defining an alias for it is likely to cause more confusion than it's worth. Every knowledgeable C programmer knows what unsigned long long int means. Nobody knows what your alias means without looking it up, and even then they can't be sure the meaning won't change as the software evolves. If you want to use unsigned long long int, it's best to use unsigned long long int (or unsigned long long).
You can define your own typedef. Remember that typedef doesn't define a new type. It only defines a new name for an existing type.
uint64_t, defined in <stdint.h>, may or may not be an alias for unsigned long long int, depending on the implementation. unsigned long long int is guaranteed to be at least 64 bits, but it could be wider (though I know of no implementations where it's not exactly 64 bits wide). Similarly, uintmax_t is likely to be unsigned long long int, but that's not guaranteed either.
You can define an alias if you like, but I wouldn't recommend it unless you need a name for some type that just happens to be defined as unsigned long long int. If you can give your typedef a name that has meaning within your application, that's probably a good idea. If its only meaning is "a shorter name for unsigned long long, I'd advise against it.
If you need a 64-bit unsigned integer type, uint64_t already exists; just use that. (And if the implementation doesn't provide a type with the required characteristics, then it won't define uint64_t and the error message when you try to use it will tell you that.)
Do I have to make my own type?
You can typedefine whatever name you wish for whatever type (inside the defined naming rules of course), keep in mind that this is only an alias for the original type, hidding predefined types behind typedefs is not consensual, it is legal though.
u128int_t or uLLong?
Taking the above paragraph in consideration, uLLong is perfectly fine. As of today there is no primitive 128 bit wide type in C, u128int_t would be misleading, I would avoid it.
uint64_t is guaranteed to have 64 bits, unsigned long long int is not, it has to have at least 64 bits, but it is not guaranteed by any rule that it should have only that.
Some compilers (for example gcc) support 128bit integers as an extension
example:
__int128_t mul(__int128_t x, __int128_t y)
{
return x * y;
}
https://godbolt.org/z/c8bW1xYdh
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.
Maybe I don't find other functions, but all functions that deals with endianness that I find accept only unsigned variable. My question is why (or are there functions that deals with endianness and accept signed variable) ?
List of functions I find : here and here.
Maybe solution is to use these macro ? What is the difference between macro and above function ?
Since endianness is implementation defined, it is safe to assume that you are talking about an implementation and not C standard. Looking at the links you have sent, I think you refer to Linux and GNU C compiler.
Then under this implementation it is safe to first type pun the signed int to unsigned int, change the endianness and type pun it back.
Following is one way of doing it
union signed_unsigned {
signed long a;
unsinged long b;
} converter;
signed long to_convert = .... //whatever value
converter.a = to_convert;
converter.b = htonl(converted.b);
to_convert = converter.a;
You can make this into a macro or a function as you see fit.
As suggested by #underscore_d, the other way to type pun a signed long to unsigned long (and back) is using pointer cast. That is valid in both C and C++ (although in C++ you should use reinterpret_cast rather than C style pointer casts).
You can use the following way to achieve the same.
signed long to_convert = .... //whatever value
unsigned long temp = *(unsinged long*)&to_convert;
temp = htonl(temp);
to_convert = *(signed long*)&temp;
I'm trying to implement some code in an Atmel datasheet. I have directly copied it from the datasheet below.
(unsigned int) (*IAP_Function)(unsigned long);
void main (void)
{
unsigned long FlashSectorNum = 200; //
unsigned long flash_cmd = 0;
unsigned long flash_status = 0;
unsigned long EFCIndex = 0; // 0:EEFC0, 1: EEFC1
/* Initialize the function pointer (retrieve function address from NMI vecto*/
IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008;
/* Send your data to the sector here */
/* build the command to send to EEFC */
flash_cmd = (0x5A << 24) | (FlashSectorNum << 8) | AT91C_MC_FCMD_EWP;
/* Call the IAP function with appropriate command */
flash_status = IAP_Function (EFCIndex, flash_cmd);
}
This enables me to call a function in ROM to program the flash that runs the code in the micro.
I'm using the gcc for ARM Cortex and get an error for the first line:
expected identifier or ‘(’ before ‘unsigned’
Now, I just changed that to:
unsigned int (*IAP_Function)(unsigned long);
As it looked wrong (not sure why the return value from a function should be in brwackets) and that error went away.
However, this line:
IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008;
Throws up the error:
expected expression before ‘)’ token
With the cursor being by the ) next to the *.
Unsurprisingly, I also get the error:
too many arguments to function ‘IAP_Function’
For the line:
flash_status = IAP_Function (EFCIndex, flash_cmd);
I suspect the datasheet has been poorly written in terms of that last error and, indeed, the first error.
However, the line:
IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008;
I do not understand. I believe, it is trying to get the contents of 0x00800008, and use that as the pointer to the function. If that is correct, how should I write that line?
Also, are my other assumptions correct in terms of ignoring the brackets around unsigned int in the first line for the value returned from the function? Also, I assume I should just change that first line to be:
unsigned int (*IAP_Function)(unsigned long, unsigned long);
As the function call needs two values?
Many thanks :)
Line IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008; casts integer to a function pointer address and assigns it to IAP_Function. Cast is required, because any self-respecting compiler should throw warning if you try to assign integer to pointer without a cast.
But as you noted return type doesn't match and for some reason there are parenthesis around it. So proper cast would look like:
IAP_Function = (unsigned int (*)(unsigned long))0x00800008;
And if you need another parameter, do add that also. Datasheet code examples are often lies, so do read carefully what manual says about the function parameters.
You should consider declaring typedef of function pointer to make sense out of this madness:
typedef unsigned (*FuncType)(unsigned long, unsigned long);
FuncType IAP_Function;
...
IAP_Function = (FuncType)0x00800008; // Nice and simple
Actually, IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008; doesn't uses content of 0x00800008 as a pointer to function. It uses 0x00800008 as the address itself.
In your definition you declared IAP_Function as a function that returns unsigned int, however, when you're casting you cast to function that returns unsigned long.
Also, function takes just one argument and you're passing two. You should either change your cast and function declaration or pass only one argument.
To match the call at the bottom, the function pointer declaration at the top should be
unsigned long (*IAP_Function)(unsigned long, unsigned long);
However, the correct thing to do depends on the function that is assigned to the pointer, which you have not described.
It is out of the primary topic, but I report my result, as I found first this page for my original problem with the IAP_Function() in question.
After some tries I successfully used the IAP_Function() (a clear GPNVM Bit operation) with SAM3A8C, in the following way. The address in not 0x00800008, but 0x00100008 (I found this tip elsewhere), and IAP_Function() takes only one long argument, as described in chapter 20.5.2 of the Atmel manual. I don't know if the 0x00800008 address works similarly, but with two arguments (with EFCIndex), or these are mistypings in the manual.
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 *.