Forum: Compiler & IDEs GCC ARM Embedded -> Compiler bug! Dereferenzierung von Pointern.


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Ma H. (Gast)


Lesenswert?

GCC scheint offenbar ein Problem mit der dereferenzierung von Pointern 
zu haben. Hier der Beispiel code:
1
#define    MAX_A    4
2
#define    MAX_AS  5
3
4
typedef    char    str16[16];
5
6
typedef    struct  stc_a*    ptr_stc_a;
7
8
typedef    struct  stc_a  {
9
                            U8        number_a;
10
                            str16     text_a;
11
                          } t_a, *ptr_t_a;
12
                        
13
typedef    t_a            arr_t_a[MAX_AS];
14
typedef    arr_t_a*       ptr_arr_t_a;
15
16
17
typedef    struct  stc_b*   ptr_stc_b;
18
19
typedef    struct  stc_b    {
20
                              U8              number_b;
21
                              ptr_arr_t_a     arr_a;
22
                            } t_b, *ptr_t_b;
23
24
                          
25
#define    PTR_ARR_A      (ptr_arr_t_a)&array_a
26
27
const      arr_t_a        array_a = {
28
                                      {0,"ZERO\0"},
29
                                      {1,"ONE\0"},
30
                                      {2,"TWO\0"},
31
                                      {3,"THREE\0"},
32
                                      {4,"FOUR\0"}
33
                                    };
34
                          
35
          t_b            b        = { 0, PTR_ARR_A };
36
          
37
          ptr_t_b        ptr_b;        
38
          
39
40
#define    CR      PUTCH0('\r')          
41
          
42
void test_stc(void)
43
{
44
  U8    i;  
45
46
  ptr_b = (ptr_t_b)&b;
47
  
48
  CR;
49
  my_prints("TEST\r");
50
  my_printf("ptr_b            = %lp\r",ptr_b);
51
  my_printf("&b               = %lp\r",&b);
52
  my_printf("&array_a         = %lp\r",&array_a);
53
  
54
  my_printf("sizeof(t_a)      = 0x%02X\r",sizeof(t_a));
55
  my_printf("sizeof(arr_t_a)  = 0x%02X\r",sizeof(arr_t_a));
56
  my_printf("sizeof(t_b)      = 0x%02X\r",sizeof(t_b));
57
  
58
  CR;
59
  my_prints("Addresses dereferencing ptr_b \r");
60
  my_printf("ptr_b->number_b = %lp\r",&(ptr_b->number_b));
61
  for(i=0;i<MAX_AS;i++)
62
  {
63
    my_printf("ptr_b->arr_a[%d] = %lp\r",i,&(ptr_b->arr_a[i]));
64
  }
65
  
66
  CR;
67
  my_prints("Addresses const array_a in FLASH \r");
68
  my_printf("&array_a = %lp\r",&(array_a));
69
  for(i=0;i<MAX_AS;i++)
70
  {
71
    my_printf("&array_a[%d] = %lp\r",i,&(array_a[i]));
72
  }  
73
}


Debug Ausgabe (UART)
1
MCU          : Spansion FM3 MB9BF516N ARM Cortex-M3
2
Firmware     : v00.02
3
CM3 CMSIS    : v04.30
4
GNUC         : v05.02.01 (46712)
5
Compiled     : Feb 29 2016 @ 13:28:05
6
7
TEST
8
ptr_b            = 0x1fff8038
9
&b               = 0x1fff8038
10
&array_a         = 0xba5c
11
sizeof(t_a)      = 0x11
12
sizeof(arr_t_a)  = 0x55
13
sizeof(t_b)      = 0x08
14
15
Addresses dereferencing ptr_b 
16
ptr_b->number_b            = 0x1fff8038
17
ptr_b->arr_a[0]            = 0xba5c
18
ptr_b->arr_a[1]            = 0xbab1
19
ptr_b->arr_a[2]            = 0xbb06
20
ptr_b->arr_a[3]            = 0xbb5b
21
ptr_b->arr_a[4]            = 0xbbb0
22
23
Addresses const array_a in FLASH 
24
&array_a                   = 0xba5c
25
&array_a[0]                = 0xba5c
26
&array_a[1]                = 0xba6d
27
&array_a[2]                = 0xba7e
28
&array_a[3]                = 0xba8f
29
&array_a[4]                = 0xbaa0

Wie man sieht wird bei der Derefenzierung des Arrays über 
"ptr_b->arr_a[x]" der pointer mit sizeof(arr_t_a) incrementiert anstatt 
den anstatt mit sizeof(t_a)...

Irgendwelche ideen/workarounds???
Hab das Problem auch schon auf launchpad gepostet. Nur reagiert da 
keiner...

[Mod: Code-Tags ergänzt]

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Ma H. schrieb:
> Hab das Problem auch schon auf launchpad gepostet. Nur reagiert da
> keiner...

Wenn der Code da genauso unleserlich aussieht wie hier, ist das kein 
Wunder.

Oliver

von Dr. Sommer (Gast)


Lesenswert?

Schönes Verwirrspiel hast du da gebaut!

Ma H. schrieb:
> Wie man sieht wird bei der Derefenzierung des Arrays über
> "ptr_b->arr_a[x]" der pointer mit sizeof(arr_t_a) incrementiert anstatt
> den anstatt mit sizeof(t_a)...

Ist doch absolut korrekt, und kein Compiler Bug.
ptr_b->arr_a ist ein Zeiger auf ein Array von Typ arr_t_a. Somit sind 
Zugriffe auf ptr_b->arr_a[i] logischerweise immer auf Vielfache der 
Größe von arr_t_a.
Natürlich hast du nur 1 Array, somit sind Zugriffe mit i>0 illegal.
Wolltest du vielleicht einfach schreiben:
1
(*ptr_b->arr_a) [i]

So wird erst auf das Array zugegriffen, und dann auf dessen i-tes 
Element.

von Sebastian V. (sebi_s)


Lesenswert?

Warum hast du 2 Threads, einen auf deutsch und den anderen auf englisch, 
erstellt?

https://embdev.net/topic/391313#new

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Die ganzen typedefs und defines sind ein klassisches Beispiel für von 
hinten durch die Brust ins Auge, und dabei selbst und Knie geschossen.

Oliver

von Ma H. (Gast)


Lesenswert?

Dann mal so...

vielleicht wird es dann etwas klarer!!

1
  uint8_t        number;  
2
  ptr_arr_t_a   paa = &array_a;;

Zugriff auf das member "number_a" im i-ten Element des "array_a"  :
1
  number = array_a[i].number_a ;


Wie Dr. Sommer korrekterweise gezeigt hat ist

Zugriff auf das member "number_a" im i-ten Element des "array_a"  über 
den Pointer paa :
1
  number = (*paa)[i].number_a;

Es gilt aber auch :  (*qualifier).member == qualifier->member

Ist der "qualifier" vom typ "x" als array deklariert,
z.b. "typdef   x    qualifier[size]"

muß der Compiler zwingend auch den Pointer um sizeof(x) incrementieren 
(KR A.7.1)
1
A.7.1.
2
3
If the type of an expression or subexpression is "array of T," for some type T, then
4
the value of the expression is a pointer to the first object in the array, and the type of
5
the expression is altered to ''pointer to T." This conversion does not take place if the
6
expression is the operand of the unary & operator, or of ++, --, sizeof, or as the left
7
operand of an assignment operator or the . operator. Similarly, an expression of type
8
"function returning T," except when used as the operand of the & operator, is converted
9
to "pointer to function returning T."


Sowie KR A7.3

-> group left to right !!!
1
A7.3 Postfix Expressions
2
The operators in postfix expressions group left to right.
3
4
postfix -expression:
5
   primary-expression
6
   postfix-expression [ expression ]
7
   postfix-expression ( argument-expression-listopt
8
   postfix-expression . identifier
9
   postfix-expression -> identifier
10
   postfix-expression ++
11
   postfix-expression --
12
13
argument-expression-list:
14
  assignment -expression
15
  argument-expression-list , assignment-expression
16
17
A7.3.1 Array References
18
19
A postfix expression followed by an expression in square brackets is a postfix expression
20
denoting a subscripted array reference. One of the two expressions must have type
21
"pointer to T', where T is some type, and the other must have integral type; the type of
22
the subscript expression is T. The expression E 1 [ E2] is identical (by definition) to
23
* ( ( E 1 ) + ( E2) ) . See §A8.6.2 for further discussion.


und Auszug KR A.8.6.2
1
A8.6.2 Array Declarators
2
3
.
4
.
5
The array subscripting operation is defined so that E1[E2] is identical to
6
*(E1 + E2). Therefore, despite its asymmetric appearance, subscripting is a commutative
7
operation. Because of the conversion rules that apply to + and to arrays (§§A6.6,
8
A7.1, A7.7), if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th
9
member of E1.
10
.
11
.


1
  number = paa[i]->number_a;

Da die in der BNF von ANSI C so vorgesehen ist.
1
%token int_const char_const float_const id string enumeration_const
2
%%
3
4
postfix_exp    : primary_exp
5
              | postfix_exp '[' exp ']'
6
              | postfix_exp '(' argument_exp_list ')'
7
              | postfix_exp '('      ')'
8
              | postfix_exp '.' id
9
              | postfix_exp '->' id
10
              | postfix_exp '++'
11
              | postfix_exp '--'
12
              ;
13
14
primary_exp    : id
15
              | const
16
              | string
17
              | '(' exp ')'
18
              ;
19
20
exp            : assignment_exp
21
              | exp ',' assignment_exp
22
              ;
23
24
assignment_exp    : conditional_exp
25
                  | unary_exp assignment_operator assignment_exp
26
                  ;
27
28
assignment_operator  : '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' | '>>=' | '&=' | '^=' | '|='
29
                    ;
30
31
unary_exp    : postfix_exp
32
            | '++' unary_exp
33
            | '--' unary_exp
34
            | unary_operator cast_exp
35
            | 'sizeof' unary_exp
36
            | 'sizeof' '(' type_name ')'
37
            ;
38
39
typedef_name    : id
40
                ;
41
42
>  assignment_exp
43
>  unary_exp assignment_operator assignment_exp
44
>  (postfix_exp) assignment_operator assignment_exp
45
>  (primary_exp) assignment_operator assignment_exp
46
>  (id) assignment_operator assignment_exp
47
>  number (assignment_operator) assignment_exp
48
>  number = (assignment_exp)
49
>  number = unary_exp assignment_operator assignment_exp
50
>  number = (unary_exp) assignment_operator assignment_exp
51
>  number = (postfix_exp) assignment_operator assignment_exp
52
>  number = (postfix_exp '->' id) assignment_operator assignment_exp
53
>  number = ((postfix_exp '[' exp ']')) '->' id) assignment_operator assignment_exp
54
>  number = ((primary_exp '[' exp ']')) '->' id) assignment_operator assignment_exp
55
>  number = ((id '[' exp ']')) '->' id) assignment_operator assignment_exp
56
>  number = ((paa '[' exp ']')) '->' id) assignment_operator assignment_exp
57
.
58
.
59
>  number = ((paa '[' const ']')) '->' id) assignment_operator assignment_exp
60
>  number = ((paa '[' 1 ']')) '->' id) assignment_operator assignment_exp
61
.
62
.
63
.
64
65
66
Am Schluss
67
  number = paa[i]->number_a;

..und sry ich kenne Compiler die das so umsetzen und den pointer auf das 
N-te Element des arrays setzten (e.g. Softune IDE)!!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ma H. schrieb:
> Dann mal so...
>
> vielleicht wird es dann etwas klarer!!
> [gefühlte 100e Zeilen folgen]

Sorry, viel zu lang. Da macht sich keiner die Mühe, das durchzulesen, 
geschweige denn auch noch zu verstehen.

Schreibe bitte einen 3-bis-8-Zeiler, der das Problem verdeutlicht und 
compilierbar(!) ist.

Dazu noch maximal 3 Zeilen Text. Das reicht.

von Ma H. (Gast)


Lesenswert?

OK.. Ich seh nur Schwätzer hier...!!

Bye Bye

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ma H. schrieb:
> OK.. Ich seh nur Schwätzer hier...!!

Nein, Leute aus der Praxis, die sich so ein undurchdringliches Stück
Code wie da oben nicht freiwillig antun würden.

Hab's gerade versucht, sorry.

Bevor du den Standard zitierst, solltest du erstmal die Begriffe
lernen.  Ein "qualifier" ist im Standard etwas ganz anderes als das,
wie du den Begriff hier benutzt (und das stiftet mehr als Verwirrung).

Du kannst dem GCC übrigens ruhig zutrauen, dass er die Zeigerarithmetik
prinzipiell beherrscht, der macht das nicht erst seit gestern.

von Oliver S. (oliverso)


Lesenswert?

Ma H. schrieb:
> OK.. Ich seh nur Schwätzer hier...!!

Ansehen. Nachdenken. Verstehen...
1
#include <stdio.h>
2
3
int main()
4
{
5
6
  int arr[5] = {0,1,2,3,4};
7
  int* parr = arr;
8
  int (*pparr)[5] = &arr;
9
10
  int i;
11
  for (i=0;i<5;i++)
12
    printf("arr[%d] : %x\n", i, (unsigned int)&arr[i]);
13
  printf("\n");
14
15
  for (i=0;i<5;i++)
16
    printf("parr[%d] : %x\n", i, (unsigned int)&parr[i]);
17
  printf("\n");
18
19
  for (i=0;i<5;i++)
20
    printf("pparr[%d] : %x\n", i, (unsigned int)&pparr[i]);
21
  printf("\n");
22
23
  printf("=======================\n");
24
25
  typedef struct
26
  {
27
    int foo;
28
    int *parr;
29
  } tsparr;
30
  tsparr sparr = {0, parr};
31
  tsparr* psparr = &sparr;
32
33
  typedef struct
34
  {
35
    int foo;
36
    int (*pparr)[5];
37
  } tspparr;
38
  tspparr spparr = {0, pparr};
39
  tspparr* pspparr = &spparr;
40
41
  for (i=0;i<5;i++)
42
    printf("psparr->parr[%d] : %x\n", i, (unsigned int)&(psparr->parr[i]));
43
  printf("\n");
44
45
  for (i=0;i<5;i++)
46
    printf("pspparr->pparr[%d] : %x\n", i, (unsigned int)&(pspparr->pparr[i]));
47
48
  return 0;
49
}

Oliver

von (prx) A. K. (prx)


Lesenswert?

Ma H. schrieb:
> OK.. Ich seh nur Schwätzer hier...!!

Wenn du richtige und zielführende Antworten als Geschwätz ansiehst, 
wären dir falsche und irreführende Antworten lieber? Manchmal haben 
Experten einen besseren Blick darauf, was Geschwätz ist und was Hinweis.

Du solltest mal versuchen, den Unterschied zwischen dem Pointer auf ein 
Array-Element und dem Pointer auf ein ganzes Array zu erkennen.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Alter Schwede.

Der Code muss mit der Option

--do-what-i-mean-not-what-i-say --fno-dim-witted

übersetzt werden. Dann klappt das.

von Tassilo H. (tassilo_h)


Lesenswert?

Weil ich gute Laune habe:
Dein struct-member arr_a ist ein Pointer auf den Typ arr_t_a. Ein 
arr_t_a ist ein Array mit MAX_AS=5 Eintraegen von Typ t_a. Also hat GCC 
recht, denn du greifst mit &(ptr_b->arr_a[i]) auf das i-te Array arr_t_a 
zu (du hast aber nur eins), und nicht auf das i-te Element von deinem 
einen Array!

Ein Pointer auf ein Array ist etwas anderes als ein Pointer auf den 
ersten Eintrag, du musst einmal öfter dereferenzieren 
(*(ptr_b->arr_a))[i].

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@  Tassilo H. (tassilo_h)


>Ein Pointer auf ein Array ist etwas anderes als ein Pointer auf den
>ersten Eintrag,

Nein, das ist das gleiche.

1
int my_array[10];
2
3
int *pointer_to_array = &my_array;
4
5
my_array[i] = x;
6
pointer_to_array[i] = x;  // identisch
7
*(pointer_to_array+i) = x;  // identisch

Aber der Op hat einen Pointer auf einen Pointer.

>du musst einmal öfter dereferenzieren
>(*(ptr_b->arr_a))[i].

Jo.

von Sebastian V. (sebi_s)


Lesenswert?

Falk B. schrieb:
> Nein, das ist das gleiche.
>
> int my_array[10];
> int *pointer_to_array = &my_array;

Sicher? Wenn ich das als C Code compiliere kriege ich eine "incompatible 
pointer type" Warnung. Als C++ Code compiliert das gar nicht.

von Oliver S. (oliverso)


Lesenswert?

1
int my_array[10];
2
3
int *pointer_to_array = my_array;
4
// alternativ:
5
int *pointer_to_array1= &my_array[0];

Oliver

von Robert S. (robert_s68)


Lesenswert?

Offenbar handelt es sich hier um Drei-Stern-Programmierung! 
http://c2.com/cgi/wiki?ThreeStarProgrammer

von Tassilo H. (tassilo_h)


Lesenswert?

Falk B. schrieb:
> int *pointer_to_array = &my_array;

Du meinst wohl eher:
1
int *pointer_to_array = my_array;

Ein Array ist das gleiche wie der Pointer auf den ersten Eintrag (im 
Wesentlichen, d.h. bis auf die Information, wie groß das ganze Array 
ist/sizeof).

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Falk B. schrieb:
> @  Tassilo H. (tassilo_h)
>
>>Ein Pointer auf ein Array ist etwas anderes als ein Pointer auf den
>>ersten Eintrag,
>
> Nein, das ist das gleiche

Ist es nicht. Auch wenn die beiden Pointer auf die selbe Speicherstelle 
zeigen, haben sie unterschiedliche Typen. Und ein Array ist kein 
Pointer...

Oliver

von Rene H. (Gast)


Lesenswert?

Oliver S. schrieb:
> haben sie unterschiedliche Typen

Aber nur, wenn es sich nicht um ein rekursives Array handelt :-).

von Sebastian V. (sebi_s)


Lesenswert?

Oliver S. schrieb:
> Und ein Array ist kein Pointer...

Zerfällt aber in fast allen Fällen zu einem Pointer. Die einzigen Fälle 
in denen es nicht zerfällt ist wenn man den Address-Of Operator drauf 
anwendet oder sizeof.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Robert S. schrieb:
> Offenbar handelt es sich hier um Drei-Stern-Programmierung!
1
Debugging is twice as hard as writing the code in the first place. 
2
Therefore, if you write the code as cleverly as possible, you are,
3
by definition, not smart enough to debug it.
4
                                                 Brian Wilson Kernighan

von W.S. (Gast)


Lesenswert?

Ma H. schrieb:
> Dann mal so...
>
> vielleicht wird es dann etwas klarer!!

Nein, auch wenn du noch weitere 100 Zeilen hinzufügst, wird das nicht 
besser und schon garnicht klarer. Auch nicht mit 3 Ausrufungszeichen.

Ich geb dir nen Rat: Lade dir mal Freepascal und lazarus herunter und 
übe 1 Jahr lang mal ordentlich in Pascal zu programmieren. Entweder du 
gewöhnst dir dabei an, sauberen und "biederen" Code zu schreiben, was du 
dann im Anschluß auch in C tun könntest oder bei dir ist Hopfen&Malz 
verloren.

Ich kann es partout nicht ausstehen, wenn Leute beim Codeschreiben 
unbedingt irgendwelche grandiosen Husarenstücke vollbringen wollen. Man 
kann wirklich ALLES auch auf einfache, eben biedere Art formulieren - 
und das wird dann sowohl regelmäßig bedeutend lesbarer als auch von 
Anfang an fehlerärmer sein als jede Quellcode-Kunststückchen, wie du sie 
weiter oben zu vollführen versuchst.

Also mein wirklich GANZ ERNST gemeinter Rat: Verzichte auf 
Kunststückchen und schreib deine Quellen auf einfache Art. Benutze ruhig 
auch lokale Variablen zwecks klarerer Lesbarkeit. Dabei kannst du drauf 
vertrauen, daß dies deine Firmware nicht verlangsamt, denn der Compiler 
kann sowas besser optimieren als du selber.

W.S.

von Falk B. (falk)


Lesenswert?

Oder kurz und prägnant.

K.I.S.S.

https://de.wikipedia.org/wiki/KISS-Prinzip

Beitrag #7414685 wurde von einem Moderator gelöscht.
Beitrag #7414943 wurde von einem Moderator gelöscht.
Beitrag #7416084 wurde von einem Moderator gelöscht.
Beitrag #7416135 wurde von einem Moderator gelöscht.
Beitrag #7416526 wurde von einem Moderator gelöscht.
Beitrag #7416774 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.