Forum: PC-Programmierung Funktionsaufruf springt an falsche Adresse


von Jan S. (jannemann)


Lesenswert?

Hallo, ich habe ein Problem bei der Übergabe einer Struktur in C.

beim Aufruf der Funktion
1
unsigned char uc_fifo_push(struct uc_fifo *buffer, unsigned char sign)
 wird nicht die gewünschte Struktur übergeben, sondern es wird eine neue 
Struktur erzeugt, die nicht initalisiert ist.

Die Variable
1
fifo
 aus der main-Funktion wird in
1
uc_fifo_init()
 korrekt initialisiert (size=5, write=read=0). In der Funktion
1
uc_fifo_push()
 sind size, read und write nicht mehr initialisiert.

Für die dynamische Initialisierung habe ich mich an diesem Beispiel 
orientiert: 
http://stackoverflow.com/questions/1558025/c-initialize-array-within-structure/1558037#1558037

Alle Beispiele, die ich im Netz finde kommen ohne dyn Initialisierung 
aus, oder haben einen komplett anderen Aufbau der Struktur. Ich möchte 
aber nicht alles umstricken. Nur das nötigste...
Ich hoffe jemand kann mir sagen, welchem dusseligen Fehler ich mal 
wieder aufgesessen bin.
Das Minimalbeispiel sollte ohne Probleme kompilieren.

Danke im voraus!
Jan
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
typedef struct uc_fifo
5
{
6
    unsigned char size;
7
    volatile unsigned char write;
8
    volatile unsigned char read;
9
    unsigned char data[];
10
}*uc_fifo;
11
12
uc_fifo uc_fifo_init(unsigned char size)
13
{
14
  uc_fifo fifo;
15
  //            size of data[] + size of size, write and read;
16
  size_t memory=size*sizeof(unsigned char)+3*sizeof(unsigned char);
17
  if((fifo=malloc(memory))==NULL)
18
    return NULL;
19
  else
20
  {
21
    fifo->size=size;
22
    fifo->write=0;
23
    fifo->read=0;
24
    return fifo;
25
  }
26
}
27
28
unsigned char uc_fifo_push(struct uc_fifo *buffer, unsigned char sign)
29
{
30
  if((buffer->write == buffer->size-1 && buffer->read == 0) || (buffer->write+1 == buffer->read))
31
    return 0;     // return false (buffer is full)
32
  else
33
  {
34
    buffer->data[buffer->write]=sign;
35
    if(buffer->write == buffer->size-1)
36
      buffer->write = 0;
37
    else
38
      buffer->write++;
39
    return 1;     // return success
40
  }
41
}
42
43
int main(void) {
44
  uc_fifo fifo=uc_fifo_init(5);
45
  unsigned char i=0;
46
  i=uc_fifo_push(&fifo, 0); //0 im Fifo speichern, Rückgabe=1=success
47
  return 1;
48
}

von Tom (Gast)


Lesenswert?

Compiler-Warnungen auf maximal gedreht?

uc_fifo fifo=uc_fifo_init(5); // ist ein pointer auf ein struct uc_fifo
uc_fifo_push(&fifo, 0); // will ein (struct uc_fifo *), bekommt aber die 
adresse des pointers.


Entweder das struct weg-typedefen oder kein typedef, aber beides mit 
gleichem Namen mischen ist böse.

von Tom (Gast)


Lesenswert?

Jan S. schrieb:
> Das Minimalbeispiel sollte ohne Probleme kompilieren.

Tom schrieb:
> Compiler-Warnungen auf maximal gedreht?

Nachtrag:
Selbst mit Standard-Einstellungen meckert der gcc schon:

1.c: In function ‘main’:
1.c:46:3: warning: passing argument 1 of ‘uc_fifo_push’ from 
incompatible pointer type [enabled by default]
1.c:28:15: note: expected ‘struct uc_fifo *’ but argument is of type 
‘struct uc_fifo **’

Wenn man auf funktionierende Software Wert legt, sollte man
Warnungen immer als Fehler betrachten, solange man die Bedeutung nicht 
genau verstanden hat.

von PittyJ (Gast)


Lesenswert?

Nimm mal den Pointer Type aus dem typedef raus. Dann wird klarer, wann 
ein Pointer benutzt wird.

typedef struct uc_fifo
{
    unsigned char size;
    volatile unsigned char write;
    volatile unsigned char read;
    unsigned char data[];
} uc_fifo_t;

Dann
 uc_fifo_t *fifo;
nehmen

Für das malloc kann dann
 sizeof(uc_fifo_t)
genommen werden.

Und das offene Array mit data geht gar nicht. Dafür sollte ein eigenes 
Malloc benutzt werden. Also
 unsigned char *data;
 data = malloc(size);

So machen das viele Programmierer, und man blickt leichter durch fremden 
Code.

von Daniel A. (daniel-a)


Lesenswert?

PittyJ schrieb:
> Und das offene Array mit data geht gar nicht. Dafür sollte ein eigenes
> Malloc benutzt werden.

Ist das nicht nur eine gnu-extension? Entweder einen Pointer nehmen und 
ein 2tes malloc, oder eine Minimalgrösse>0 angeben:
unsigned char data[1];

von Rolf Magnus (Gast)


Lesenswert?

Daniel A. schrieb:
> Ist das nicht nur eine gnu-extension?

Nein, das ist Standard-C, und zwar genau, damit man sowas machen kann.

Aus der C99-ISO-Norm:

"A structure or union shall not contain a member with incomplete or 
function type (hence, a structure shall not contain an instance of 
itself, but may contain a pointer to an instance of itself), except that 
the last member of a structure with more than one named member may have 
incomplete array type"

von Rolf Magnus (Gast)


Lesenswert?

Kurz am Rande noch:
1
  //            size of data[] + size of size, write and read;
2
  size_t memory=size*sizeof(unsigned char)+3*sizeof(unsigned char);

Das ist sehr umständlich geschrieben, denn sizeof(unsigned char) ist per 
Definition in C immer 1. Das oben ist also das gleiche wie:
1
size_t memory = size + 3;

Aber warum nicht gleich:
1
size_t memory = size + sizeof(struct uc_fifo);

von Jan S. (jannemann)


Lesenswert?

Ist mir ein bisschen unangenehm, dass ich euch so lange auf eine Antwort 
zu den vielen Hilfestellungen warten lasse! Musste kurzfristig meine 
Prios ändern und dann war plötzlich Urlaubszeit...

Tom schrieb:
> Entweder das struct weg-typedefen oder kein typedef, aber beides mit
> gleichem Namen mischen ist böse.
Habe ich getan. Vielen Dank für den Hinweis Tom. ich nutze jetzt 2 
verschiedene Namen (siehe PittyJ)
1
typedef struct uc_fifo_t {...} uc_fifo;

PittyJ schrieb:
> Nimm mal den Pointer Type aus dem typedef raus. Dann wird klarer, wann
> ein Pointer benutzt wird.
Auch hierfür vielen Dank. Das war einfach nur Copy+Paste ohne 
nachzudenken, was da eigentlich geschieht. Den Pointer habe ich aus dem 
typedef entfernt, so wird es (mir) wesentlich klarer.

Rolf Magnus schrieb:
> Aber warum nicht gleich:size_t memory = size + sizeof(struct uc_fifo);
Ich fand es so irgenwie intuitiver. Aber du hast recht. Das einzelne 
Aufsummieren geht nur bei kleinen Strukturen, die sich in zukünfigen 
Versionen nicht mehr ändern. Bei großen, unübersichtlichen Strukturen 
oder zukünftigeren Code-Änderungen wird es mit meiner Methoder sehr 
kompliziert und fehleranfällig.

Recht herzlichen Dank euch allen! Und noch einmal Entschuldigung, 
wegender späten Antwort.

Beste Grüße Jan

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.