Using the latest Keil C compiler (V7.00) Executing on an Infineon XC161CJ-16F This code appears to produce the wrong result.
At the "if" statement I expect v1 to equal v3 and for the main function to return 0 (I don't actually want to use the return value, its just a mock up piece of code). However, at the "if" statement, the value of v1 is 0x1234 and the value of v3 is 0xB1234.
Can anyone explain why?
typedef unsigned long ULONG; typedef unsigned short USHORT; typedef BYTE * POINTER; POINTER v1,v2,v3,v4; ULONG temp_ptr; int main(void) { v1 = (POINTER)0; v2 = (POINTER)0x0B1234; v1 += (ULONG)v2; // This assigns 0x1234 to v1, I think it should assign 0xB1234 v3 = (POINTER)0; v4 = (POINTER)0x0B1234; temp_ptr = (ULONG)v3; v3 = temp_ptr+v4; // This statement assigns 0xB1234 to v3 correctly. if ( v1!=v3 ) return -1; else return 0; }
@Hans-Bernhard Broeker How can you do this without casting?
int *hardware_address = (int *)0x7FFF;
We can't. But that means those of us needing to do that have to find something else, beside the language itself, to base any expectations about what this actually does on.
You've gone to great lengths to try and convince me that assigning pointers to integers and integers to pointers is undefined in C. It is not undefined you are wrong about that. It is implementation specific. I started this thread to try and discover the specifics of the Keil compiler's implementation of such things...
From the ANSI C specification (my emphasis).
3.3.4 Cast operators <snip> Conversions that involve pointers (other than as permitted by the constraints of $3.3.16.1) shall be specified by means of an explicit cast; they have implementation-defined aspects: A pointer may be converted to an integral type. The size of integer required and the result are implementation-defined. If the space provided is not long enough, the behavior is undefined. An arbitrary integer may be converted to a pointer. The result is implementation-defined./37/
I understand that the results of such pointer casting are implementation specific. However the ANSI C standard does not specify such operations to be undefined.
The only thing that can make those operations undefined is the implementation, i.e. the Keil compiler. All I am asking is why should the Keil compiler define the two examples I gave differently?
Regards Paul
After studying the assembler I realize my original sample code is wrong. It should have been like this:
typedef unsigned long ULONG; typedef unsigned short USHORT; typedef char * POINTER; POINTER v1,v2,v3,v4; ULONG temp_ptr; int main(void) { v1 = (POINTER)0x0B0000; v2 = (POINTER)0x1234; v1 += (ULONG)v2; v3 = (POINTER)0xB0000; v4 = (POINTER)0x1234; temp_ptr = (ULONG)v4; v3 = v3+temp_ptr; if ( v1!=v3 ) return -1; else return 0; }
In the code above, at no stage am I adding more than 0xFFFF to any huge pointer and it all works as expected. For the longest time in this thread, I did not "get" that I was adding more than 0xFFFF to a huge pointer, firstly because I had thought (incorrectly) I was using XLarge memory model and for a few hours after that, because I was being a little bit thick.
So that just leaves the final question as to why this original code:
v3 = (POINTER)0; v4 = (POINTER)0x0B1234; temp_ptr = (ULONG)v3; v3 = temp_ptr+v4;
produced the expected result. Putting on my "thinking clearly" hat which I had obviously not been wearing before...
The calculation is adding a pointer (v4) to an integer (temp_ptr) the pointer is already pointing at 0xB1234 so adding an integer of value 0 will result in a pointer of 0xB1234.