Forum: Mikrocontroller und Digitale Elektronik Pointerrückgabe C Funktion unklar


von C. L. (calle)


Lesenswert?

Hi!

Ich komme nicht ganz klar mit dem Übergeben und der Rückgabe von 
Pointern einer C Funktion.
Alles was ich machen will ist ein übergebenes Byte in einer Funktion zu 
drehen und es wieder zurückzugeben.
Ich habe ein Array mit 12 Bytes, diese müssen alle gedreht werden (nicht 
invertiert).
Deklariert habe ich folgendes:
1
// Daten ungedreht
2
unsigned char Data[12] = {0x5B, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
3
4
// Speicher für gedrehte Daten
5
unsigned char DataGedreht[12];

Jetzt habe ich eine Routine geschrieben, welche ich das Ausgangsarray 
übergeben möchte und die Funktion soll mir dann die gedrehten Daten 
zurückschreiben in das andere Array.
Ich kriegs nicht hin; Verständnisspropobleme!
1
 unsigned char* ByteDrehen(unsigned char *byte)
2
 {
3
 unsigned char o, *DataGedreht_ = 0;
4
 
5
 for(o=0; o<=11; o++)                                        
6
            {
7
            if ((byte[o] & 0x01) == 0x01) {DataGedreht_[o] |= 0x80;}
8
            if ((byte[o] & 0x02) == 0x02) {DataGedreht_[o] |= 0x40;}
9
            if ((byte[o] & 0x04) == 0x04) {DataGedreht_[o] |= 0x20;}
10
            if ((byte[o] & 0x08) == 0x08) {DataGedreht_[o] |= 0x10;}
11
            if ((byte[o] & 0x10) == 0x10) {DataGedreht_[o] |= 0x08;}
12
            if ((byte[o] & 0x20) == 0x20) {DataGedreht_[o] |= 0x04;}
13
            if ((byte[o] & 0x40) == 0x40) {DataGedreht_[o] |= 0x02;}
14
            if ((byte[o] & 0x80) == 0x80) {DataGedreht_[o] |= 0x01;}
15
            
16
            return &DataGedreht_[o];
17
            DataGedreht_ = 0;
18
            }
19
}

in der MAIN dann aufgerufen:
1
 *DataGedreht = ByteDrehen(&Data);

Entweder meckert der Compiler mit Implicit Ptr conversion oder er weißt 
Fehler aus und compiliert nicht.
Eigentlich sollte doch bei 0x5B dann 0xDA rauskommen usw.

Kann mich mal jemadn wieder auf die Spur setzen?

CL

von Hans (Gast)


Lesenswert?

Du musst beide Zeiger an die Funktion übergeben, auf die originalen 
Daten und auf die gedrehten Daten.
1
void dreheBytes(const unsigned char *input, unsigned char *output)
2
{
3
  for (int i = 0; i < 12; ++i)
4
  {
5
    // ...
6
    output[i] = gedrehtesByte;
7
  }
8
]

Normalerweise übergibt man auch die Länge der Daten an die Funktion, 
damit sie nicht nur mit 12 Byte funktioniert, sondern universell 
einsetzbar ist.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

C. L. schrieb:
> unsigned char o, *DataGedreht_ = 0;

Der Pointer "DataGedreht_" zeigt also auf NULL.

> DataGedreht_[o]

Da dereferenzierst Du einen Pointer, der auf NULL zeigt.

von C. L. (calle)


Lesenswert?

Ok,

das heisst dann rein nur 2 mal Übergabe und nicht als klassische 
Rückgabe mit "return".
Geht denn sowas nicht als Rückgabeparameter?

Bin allerdings auch so zufrieden.

CL

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

C. L. schrieb:
> Geht denn sowas nicht als Rückgabeparameter?

Nur, wenn Du den dafür benötigten Speicher dynamisch (mit malloc & 
Co.) anforderst, oder ihn als static innerhalb der Funktion 
deklarierst. Das aber kann unappetitliche Nebenwirkungen haben, wenn die 
Funktion mehrfach aufgerufen wird und Du an den unterschiedlichen 
Stellen annimmst, der Speicher, auf den der zurückgegebene Pointer 
zeigt, wäre unverändert.

Alternativ könntest Du auch eine globale Variable dafür anlegen, aber 
das ändert am Problem nichts und ist obendrein auch noch Pfusch und 
Murks.

von C. L. (calle)


Lesenswert?

Rufus Τ. F. schrieb:
> Pfusch und
> Murks.

;-) neee, das wollen wir ja nicht und es ist obendrein auch ziemlich 
kompliziert. Liegt aber auch an meinem Verständniss über Zeiger.
Da ist noch Luft nach oben. ;-)
Habe das dann mit den beiden Pointerübergaben im Aufruf gelöst.
Funktiniert auch!

Danke Euch.

CL

von Hans (Gast)


Lesenswert?

C. L. schrieb:
>
> Geht denn sowas nicht als Rückgabeparameter?
>

Wenn Du einen Zeiger zurückgibst, ist das einfach nur eine 
Speicheradresse, also eine Zahl. Du willst aber 12 Byte zurückgeben.

Es gäbe noch zwei andere Möglichkeiten:

1. Du gibst ein struct mit einem 12-Byte-Array zurück. Das ist 
allerdings unflexibel, weil die Funktion dann nur exakt 12 Byte 
zurückgeben kann und keine andere Längen. Je nachdem was Compiler draus 
macht, kann es auch ineffizienter sein, wenn die Daten nochmal umkopiert 
werden.

2. Du holst Dir mit malloc() 12 Byte dynamischen Speicher und gibst den 
Zeiger darauf zurück. Dann muss der Aufrufer der Funktion allerdings 
dran denken, den Speicher mit free() wieder freizugeben. Außerdem ist 
malloc() recht teuer, gerade auf einem Mikrocontroller.

Daher geht man in C meistens lieber den Weg, der Funktion einen Zeiger 
auf den Speicherbereich zu übergeben, in den sie ihre Daten schreiben 
soll.

von malsehen (Gast)


Lesenswert?

Meines Erachtens bearbeitet die Schleife aber nur

byte[0]

da

return &DataGedreht_[o];

in der Schleife steht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ja, aber bereits DataGedreht_[0] ist ungültig.

von Peter D. (peda)


Lesenswert?

Hans schrieb:
> Du musst beide Zeiger an die Funktion übergeben, auf die originalen
> Daten und auf die gedrehten Daten.

Ich würd nochmal genau überlegen, ob die alten Daten danach überhaupt 
noch gebraucht werden. Oftmals reicht nämlich ein Pointer und man 
überschreibt einfach die alten Daten.

von C. L. (calle)


Lesenswert?

Ja, das könnte man so machen und sich ein Pointer sparen.
In diesem Fall hätte ich es aber nicht machen wollen, denn die Daten im 
Ausgangsarray werden immer wieder so benötigt.
Darauf hatte ich aber nicht hingewiesen.

CL

von Adam P. (adamap)


Lesenswert?

Du könntest auch dein Problem in Teilprobleme gliedern und somit auch 
"Sauberkeit" im Code halten.

Falls du es mit Zeigern lösen möchtest, dann hätte ich dir folgendes 
Bsp.:
1
void byte_rotate(uint8_t src, uint8_t *dst)
2
{
3
  uint8_t i;
4
5
  for(i=0; i<7; i++)
6
  {
7
    *dst |= (src & 0x01);
8
    *dst = (*dst << 1);
9
    src = (src >> 1);
10
  }
11
12
  *dst |= (src & 0x01);
13
}
14
15
void array_rotate(const uint8_t *input, uint8_t *output, size_t size)
16
{
17
  uint8_t i;
18
19
  for(i=0; i<size; i++)
20
  {
21
    byte_rotate(input[i], &output[i]);
22
  }
23
}

Aufruf:
1
#define BUF_SIZE    12
2
3
uint8_t buf_orig[BUF_SIZE];
4
uint8_t buf_rotate[BUF_SIZE];
5
6
array_rotate(buf_orig, buf_rotate, BUF_SIZE);


Es gibt mehrere Lösungen das Byte zu rotieren, somit musst du nicht 
diese nehmen, ich finde es mit der Schleife nur "schöner" als in deinem 
ersten Beitrag.

Gruß

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.