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).
f_a() returns a pointer to rueck. Since rueck is a variable who's lifetime ends when the function ends, you should not assume the value written into rueck will remain there. If you don't call f_a() again before you 'use' its return value, just make rueck static to solve the problem.
f_a() returns a pointer to rueck No it doesn't, it returns an object of type two_byz. This is no different than returning an int. C can return structures "by value". If he had typed f_a() as two_byz *f_a(void) and returned &rueck you'd be right, but he didn't, so you're not. No static-ness is necessary here just as it is not necessary in the following example:
int func(void) { int value = 10; return value; }
In fact there was no problem with the function or the function calling. In this other modul, which i've mentioned, i had produced a great memory overflow. I admitt this was a really silly mistake. However, I thank you for your trouble and by the way it was useful information.
Mark, you need to look at the generated code before making such a sweeping statement. Not all compilers are created to your liking.
1 #include <stdio.h> 2 3 typedef struct { 4 5 unsigned char Byte_1; 6 unsigned char Byte_2; 7 } two_byz; 8 9 two_byz f_a(void) 10 { 11 1 two_byz rueck; 12 1 rueck.Byte_1 = 0xAA; 13 1 rueck.Byte_2 = 0xBB; 14 1 return ( rueck); 15 1 } 16 17 18 19 20 void main(void){ 21 1 two_byz test; 22 1 two_byz test2; 23 1 24 1 test = test2; 25 1 test = f_a(); 26 1 27 1 } 28 C51 COMPILER V6.10 MAIN 03/30/2001 08:39:14 PAGE 2 ASSEMBLY LISTING OF GENERATED OBJECT CODE ; FUNCTION f_a (BEGIN) ; SOURCE LINE # 9 ; SOURCE LINE # 10 ; SOURCE LINE # 12 0000 7500AA R MOV rueck,#0AAH ; SOURCE LINE # 13 0003 7500BB R MOV rueck+01H,#0BBH ; SOURCE LINE # 14 0006 7B00 MOV R3,#00H 0008 7A00 R MOV R2,#HIGH rueck 000A 7900 R MOV R1,#LOW rueck ; SOURCE LINE # 15 000C ?C0001: 000C 22 RET ; FUNCTION f_a (END) ; FUNCTION main (BEGIN) ; SOURCE LINE # 20 ; SOURCE LINE # 24 0000 7800 R MOV R0,#LOW test 0002 7C00 R MOV R4,#HIGH test 0004 7D00 MOV R5,#00H 0006 7B00 MOV R3,#00H 0008 7A00 R MOV R2,#HIGH test2 000A 7900 R MOV R1,#LOW test2 000C 7E00 MOV R6,#00H 000E 7F02 MOV R7,#02H 0010 120000 E LCALL ?C?COPY ; SOURCE LINE # 25 0013 120000 R LCALL f_a 0016 7800 R MOV R0,#LOW test 0018 7C00 R MOV R4,#HIGH test 001A 7D00 MOV R5,#00H 001C 7E00 MOV R6,#00H 001E 7F02 MOV R7,#02H 0020 020000 E LJMP ?C?COPY ; FUNCTION main (END)
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.
I may no sweeping statement, just reiterated ANSI/ISO C requirements. How the implementation actually returns a struct should not matter. The fact is the code works as if the structure was returned. That is, you don't need to return a pointer to the struct and you can still access the data of the returned struct (it doesn't dissappear when the function returns). I stand by ANSI C, the struct returned is returned as an object from the point of view of the code. How the compiler implements this facet of ANSI C is of no concern to me unless I'm worried about efficiency. Regards. - Mark