The following code (part of a simple GUI running on a 251 platform with an LCD) attempts to pass a struct which is a member of another struct on the stack. A pointer to the container struct is dereferenced using the '->' operator. The call to DrawRect below is supposed to pass certain members of the WindowContext struct, namely two ScreenPoint structs and a byte. Instead the compiler appears to be incorrectly passing the entire WindowContext struct on the stack, and therefore the DrawRect routine that receives the faulty parameters becomes hopelessly confused.
What is going on here? (Using C251 4.00) Thanks...
struct ScreenPoint { unsigned char x; unsigned char y; }; typedef struct ScreenPoint SCREENPT; typedef struct ScreenPoint SCREENSZ; struct WindowContext { SCREENPT OrgPt; SCREENSZ TotalSz; unsigned char BorderColor; /*Etc...*/ }; typedef struct WindowContext *WinPtr; void DrawRect(SCREENPT Org, SCREENSZ Sz, unsigned char Color) reentrant; TestFunction(WinPtr pWin) reentrant { DrawRect(pWin->OrgPt, pWin->TotalSz, pWin->BorderColor); }
I cannot tell about C251 V4.00, but with V4.53 which is the current version things are looking good:
C251 COMPILER V4.53d, COMPILATION OF MODULE x OBJECT MODULE PLACED IN x.OBJ COMPILER INVOKED BY: C:\Keil\C251\Bin\C251.exe x.c CODE stmt level source 1 struct ScreenPoint { 2 unsigned char x; 3 unsigned char y; 4 }; 5 6 typedef struct ScreenPoint SCREENPT; 7 typedef struct ScreenPoint SCREENSZ; 8 9 struct WindowContext { 10 SCREENPT OrgPt; 11 SCREENSZ TotalSz; 12 unsigned char BorderColor; 13 unsigned char etc[256]; // Etc. 14 }; 15 typedef struct WindowContext *WinPtr; 16 17 void DrawRect(SCREENPT Org, SCREENSZ Sz, unsigned char Color) reentrant; 18 19 TestFunction(WinPtr pWin) reentrant { 20 1 DrawRect (pWin->OrgPt, pWin->TotalSz, pWin->BorderColor); 21 1 } ASSEMBLY LISTING OF GENERATED OBJECT CODE ; FUNCTION TestFunction?_ (BEGIN) ; SOURCE LINE # 19 000000 7D23 MOV WR4,WR6 ;---- Variable 'pWin' assigned to Register 'WR4' ---- ; SOURCE LINE # 20 000002 7D02 MOV WR0,WR4 000004 0B05 INC WR0,#02H 000006 7E09B0 MOV R11,@WR0 ; A=R11 000009 CAB8 PUSH R11 ; A=R11 00000B 0B04 INC WR0,#01H 00000D 7E09B0 MOV R11,@WR0 ; A=R11 000010 CAB8 PUSH R11 ; A=R11 000012 7D02 MOV WR0,WR4 000014 7E09B0 MOV R11,@WR0 ; A=R11 000017 CAB8 PUSH R11 ; A=R11 000019 0B04 INC WR0,#01H 00001B 7E09B0 MOV R11,@WR0 ; A=R11 00001E CAB8 PUSH R11 ; A=R11 000020 09B20004 MOV R11,@WR4+0x4 ; A=R11 000024 120000 E LCALL DrawRect?_ 000027 1BFE DEC DR60,#04H ; SOURCE LINE # 21 000029 22 RET ; FUNCTION TestFunction?_ (END)
In that case, I will have to look in to my options for updating the compiler and go from there...
OK, I installed the latest update, and it still seems to be misbehaving. Any ideas?
Hard to say without further information... The struct passing is ok, does it look the same on your side ?
OK, apologies, I was not transcribing the test code accurately.
Please try it with the following modification. The WindowContext is passed as a void pointer (because we don't want TestFunction's caller to have access to the struct declaration). Apparently using the void pointer is what leads to the problem.
You should now see a loop among the PUSH instructions where it is loading the whole pWin struct onto the stack.
void TestFunction(void* p) reentrant { WinPtr pWin = (WinPtr)p; DrawRect2(pWin->OrgPt, pWin->TotalSz, pWin->BorderColor); }
Well, after bouncing this off you, I seem to have managed to track down the problem myself.
If I replace the line...
WinPtr pWin = (WinPtr)p;
...with this...
WinPtr pWin = p;
...the problem is gone. Evidently it was displeased by the explicit cast we were doing there, which was not really needed anyway.