We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I am using functions, which returns structs. This shouldn't be a problem in C. And it works mostly. But are there contexts where this is not allowed? Maybe there a conflicts because those structs are returned by using registers? for example: typedef struct { unsigned char Byte_1; unsigned char Byte_2; } two_byz; two_byz f_a(void) { two_byz rueck; rueck.Byte_1 = 0xAA; rueck.Byte_2 = 0xBB; return ( rueck); } two_byz test; test = f_a(); Again: this example does work - mostly! But as i used this module in another program there was just no return value. It is really weird, the function then behaves like void f_a(void).
My old K&R 2/ed (1988) says, "a function may return an arithmetic type, a structure, a union, a pointer, or void" The section on Function Return Values (p115) in the User's Guide 11.2000 makes no menion of how C51 returns structures or unions.
The bottom line is that, no matter how you would like it to work, the Keil compiler return structures as pointers. So if you do not immediately "consume" the returned structure, you have to worry about where the structure was originally allocated. This can cause some bugs to be as baffling as stack overflows. Here is an example. It should (and does on Microsoft VC++) print "3 = 3". On the Keil compiler, it prints "3 = 4". (Use optimization level 0. At optimization level 9 the last assignment gets left out.)
C51 COMPILER V6.10 MAIN 04/02/2001 17:35:06 PAGE 1 C51 COMPILER V6.10, COMPILATION OF MODULE MAIN OBJECT MODULE PLACED IN .\Main.OBJ COMPILER INVOKED BY: C:\PROGRAM FILES\KEIL\C51\BIN\C51.EXE .\Main.C OPTIMIZE(0,SIZE) DEBUG OBJECTEXTEND CODE stmt level source 1 #include <stdio.h> 2 #include <reg52.h> 3 4 typedef struct { 5 char Chars[2]; 6 } Struct; 7 8 Struct CharToStruct(char v) 9 { 10 1 Struct S; 11 1 12 1 S.Chars[0] = v; 13 1 S.Chars[1] = 0; 14 1 return( S ); 15 1 } 16 17 char AddIndrect( const char *S0, const char *S1) 18 { 19 1 return( *S0 + *S1 ); 20 1 } 21 22 void main(void){ 23 1 char ShouldBe3Not4; 24 1 25 1 ShouldBe3Not4 = AddIndrect( CharToStruct(1).Chars, CharToStruct(2).Chars ); 26 1 27 1 TI = 1; 28 1 printf( "3 = %d", (int)ShouldBe3Not4 ); 29 1 30 1 while(1) ; 31 1 } 32 C51 COMPILER V6.10 MAIN 04/02/2001 17:35:06 PAGE 2 ASSEMBLY LISTING OF GENERATED OBJECT CODE ; FUNCTION _CharToStruct (BEGIN) 0000 8F00 R MOV v,R7 ; SOURCE LINE # 8 ; SOURCE LINE # 9 ; SOURCE LINE # 12 0002 850000 R MOV S,v ; SOURCE LINE # 13 0005 750000 R MOV S+01H,#00H ; SOURCE LINE # 14 0008 7B00 MOV R3,#00H 000A 7A00 R MOV R2,#HIGH S 000C 7900 R MOV R1,#LOW S ; SOURCE LINE # 15 000E ?C0001: 000E 22 RET ; FUNCTION _CharToStruct (END) ; FUNCTION _AddIndrect (BEGIN) 0000 8B00 R MOV S0,R3 0002 8A00 R MOV S0+01H,R2 0004 8900 R MOV S0+02H,R1 ; SOURCE LINE # 17 ; SOURCE LINE # 18 ; SOURCE LINE # 19 0006 AB00 R MOV R3,S1 0008 AA00 R MOV R2,S1+01H 000A A900 R MOV R1,S1+02H 000C 120000 E LCALL ?C?CLDPTR 000F FF MOV R7,A 0010 AB00 R MOV R3,S0 0012 AA00 R MOV R2,S0+01H 0014 A900 R MOV R1,S0+02H 0016 120000 E LCALL ?C?CLDPTR 0019 FE MOV R6,A 001A EE MOV A,R6 001B 2F ADD A,R7 001C FF MOV R7,A ; SOURCE LINE # 20 001D ?C0002: 001D 22 RET ; FUNCTION _AddIndrect (END) ; FUNCTION main (BEGIN) ; SOURCE LINE # 22 ; SOURCE LINE # 25 0000 7F01 MOV R7,#01H 0002 120000 R LCALL _CharToStruct 0005 C003 PUSH AR3 0007 C002 PUSH AR2 0009 C001 PUSH AR1 000B 7F02 MOV R7,#02H 000D 120000 R LCALL _CharToStruct 0010 8B00 R MOV ?_AddIndrect?BYTE+03H,R3 0012 8A00 R MOV ?_AddIndrect?BYTE+04H,R2 0014 8900 R MOV ?_AddIndrect?BYTE+05H,R1 0016 D001 POP AR1 0018 D002 POP AR2 001A D003 POP AR3 001C 120000 R LCALL _AddIndrect C51 COMPILER V6.10 MAIN 04/02/2001 17:35:06 PAGE 3 001F 8F00 R MOV ShouldBe3Not4,R7 ; SOURCE LINE # 27 0021 D299 SETB TI ; SOURCE LINE # 28 0023 7BFF MOV R3,#0FFH 0025 7A00 R MOV R2,#HIGH ?SC_0 0027 7900 R MOV R1,#LOW ?SC_0 0029 AF00 R MOV R7,ShouldBe3Not4 002B EF MOV A,R7 002C 33 RLC A 002D 95E0 SUBB A,ACC 002F FE MOV R6,A 0030 8E00 E MOV ?_printf?BYTE+03H,R6 0032 8F00 E MOV ?_printf?BYTE+04H,R7 0034 120000 E LCALL _printf 0037 ?C0003: ; SOURCE LINE # 30 0037 80FE SJMP ?C0003 0039 ?C0004: ; SOURCE LINE # 31 0039 ?C0005: 0039 22 RET ; FUNCTION main (END) MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 103 ---- CONSTANT SIZE = 7 ---- XDATA SIZE = ---- ---- PDATA SIZE = ---- ---- DATA SIZE = 10 ---- IDATA SIZE = ---- ---- BIT SIZE = ---- ---- END OF MODULE INFORMATION. C51 COMPILATION COMPLETE. 0 WARNING(S), 0 ERROR(S)
"the Keil compiler return structures as pointers." As you have discovered. My point was that we shouldn't have to "discover" such things; Keil should document it in the manuals - as they have done with the other return types.
Good point.
Since we're currently working on the C51 compiler manual, I'll see about putting this in there. Jon
Great! While you're at it, how about a major overhaul of the discussion of the bit-addressing extensions? Obviously, this is totally implementation-specific and therefore needs to be given a detailed treatment in the body of the manual, rather than merely part of an appendix right at the end of the document!
There is a discussion of bit-addressable stuff in the C51 UG on P65-66. Is there more that should be said there? I've used the tools for so long that this is second-nature to me now. Jon
Since you can not use the volatile keyword with the sf bits & registers, I would feel better if it was stated that these are implicitly volatile.