Forum: Mikrocontroller und Digitale Elektronik Vektor "Rechnung" mit C


von ArduStemmi (Gast)


Lesenswert?

Hallo liebe Gemeinde!
Heute mal zurück zu den Wurzeln! Ich möchte Vektoren kopieren, wobei die 
Dimension des Quellvektors größer ist, als die Dimension des 
Zielvektors! Anders gesprochen: ich möchte aus einem Datenfeld mit x 
Elementen nur die x-3 letzten Elemente in ein neues Datenfeld kopieren! 
Bisher erledige ich das mit einer Schleife und inhärenter 
Indexmanipulation!
Gibt es einen direkten Weg in C?

Danke für Eure Hilfe!

von Jim M. (turboj)


Lesenswert?

Hmm... memcpy() würde mir da sponten einfallen.

von PittyJ (Gast)


Lesenswert?

Nein, in C gibt es keinen anderen Weg.
Schreib doch eine Funktion, an der beide Vektoren übergeben werden. Dann 
verschwinden zumindest die Schleifen aus dem Hauptprogramm.

von ArduStemmi (Gast)


Lesenswert?

Hast Du da ein Beispiel? Gern auch mehrdimensional!
Danke!

von Reinhard M. (Gast)


Lesenswert?

void *memcpy(void *str1, const void *str2, size_t n)

von Fpgakuechle K. (Gast)


Lesenswert?

ArduStemmi schrieb:

> Gibt es einen direkten Weg in C?

Je nach processor gibt des den directen Weg des direct memory access - 
DMA.
Schau mal in der Bibliotheksbeschreibung "deines" processors.

von ArduStemmi (Gast)


Lesenswert?

Ich programmiere mit ATMel Studio! Ziel ist ein ATmega 644!

von Fpgakuechle K. (Gast)


Lesenswert?

ArduStemmi schrieb:
> Ich programmiere mit ATMel Studio! Ziel ist ein ATmega 644!

Und dort ist das Datenblatt:
http://www.atmel.com/images/doc2593.pdf

von Reinhard M. (Gast)


Lesenswert?

und warum nicht memcpy ?
1
#include <stdio.h>
2
#include <string.h>
3
4
double a[50][50];
5
double b[50][50];
6
7
8
int main()
9
{
10
     for(size_t index_U = 0; index_U < 50 ; index_U ++)
11
        for(size_t index_V = 0; index_V < 50 ; index_V ++)
12
            a[index_V][index_U] = (double)(index_U * index_V);
13
14
15
     memcpy(b, a, 50*50*sizeof(double));
16
17
    for(size_t index_U = 0; index_U < 50 ; index_U ++)
18
        for(size_t index_V = 0; index_V < 50 ; index_V ++)
19
            printf("%d  %d  %f   %f\n", index_V,index_U,b[index_V][index_U], a[index_V][index_U] - b[index_V][index_U]);
20
21
}

von Eric B. (beric)


Lesenswert?

Reinhard M. schrieb:
>
>
1
>      for(size_t index_U = 0; index_U < 50 ; index_U ++)
2
>         for(size_t index_V = 0; index_V < 50 ; index_V ++)
3
>             a[index_V][index_U] = (double)(index_U * index_V);
4
>

Ich hätte da eher a[index_U][index_V] genommen, oder die Schleifen 
andersrum genestet:
1
for(size_t outer=0; ...)
2
  for(size_t middle=0; ...)
3
    for(size_t inner=0; ...)
4
      array[outer][middle][inner] = ...

von Reinhard M. (Gast)


Lesenswert?

Eric B. schrieb:
> Ich hätte da eher a[index_U][index_V] genommen, oder die Schleifen
> andersrum genestet:

Ja.
Das ist eine quick & dirty Demo, um memcpy (gerne auch mehrdimensional)
darzustellen.

Die eigentliche (Haus)Aufgabe des TO bleibt dem eigenen Fleiß 
überlassen;-)

von ArduStemmi (Gast)


Lesenswert?

Danke, ich habe jetzt das Datenblatt und die Beschreibung von memcpy. 
Ich glaube Zweiteres wird die Lösung des Problems sein können. Daher 
möchte ich noch einmal auf meine Frage kommen. Ich möchte aus einem 
Datenfeld mit 3 x 10 Elementen ein Datenfeld "entnehmen" mit 3 x 7 
Elementen. Wobei die jeweils letzten 7 zu verwenden sind. Kann da memcpy 
helfen? Ich habe verstanden, memcopy kopiert Byte für Byte einen 
Speicherbereich in einen anderen. Wobei anzugeben sind: StartAdresse des 
Quellbereichs, STARTAdresse des Zielbereichs und die Menge der zu 
kopierenden Daten.

In meinem Fall gibt es ja nicht einen, sondern im besten Fall drei 
Speicherbereiche (Elemente 3 - 10, Elemente 13 bis 20 und Elemente 23 - 
30). Demnach habe ich drei StartAdressen (3, 13, 20)!

Wenn ich dann also auch bloss eine For Schleife brauche, dann kann ich 
es auch Elementweise kopieren und weiterhin Index-Zauberei betreiben. 
(Aus Element(0,3) wird NeuElement(0,0) usw., usf.

Oder irre ich?

von Mark B. (markbrandis)


Lesenswert?

Es hindert dich niemand daran, dreimal memcpy() aufzurufen. Jeweils 
einmal für jeden zusammenhängenden Speicherbereich.

von Yalu X. (yalu) (Moderator)


Lesenswert?

ArduStemmi schrieb:
> In meinem Fall gibt es ja nicht einen, sondern im besten Fall drei
> Speicherbereiche (Elemente 3 - 10, Elemente 13 bis 20 und Elemente 23 -
> 30). Demnach habe ich drei StartAdressen (3, 13, 20)!

Wenn du das Array mit den Daten passend deklarierst, nämlich nicht als
[3][10], sondern als [10][3], sind die zu kopierenden Elemente mit den
Indizes [3..9][0..2] zusammenhängend, und ein einzelner memcpy-Aufruf
genügt.

von ArduStemmi (Gast)


Lesenswert?

Das ist eine gute Idee! Muss mal sehen, ob ich mein Datenmodell 
umstricken kann. Die Daten sind zum Teil schon im EEPROM und müssten 
auch dort umgestrickt werden.

Aber wie lautet den der memcpy Befehl, wenn ich ab dem 3. Element einer 
Auflistung zugreifen will?

von Mark B. (markbrandis)


Lesenswert?

ArduStemmi schrieb:
> Aber wie lautet den der memcpy Befehl, wenn ich ab dem 3. Element einer
> Auflistung zugreifen will?

Du kannst als Startadresse jedes beliebige Element eines Arrays angeben. 
Es muss also nicht das Element mit dem Index [0][0] sein, sondern es 
könnte auch [0][2] sein. Oder [2][0]. Oder was immer Du haben willst.

von Yalu X. (yalu) (Moderator)


Lesenswert?

ArduStemmi schrieb:
> Aber wie lautet den der memcpy Befehl, wenn ich ab dem 3. Element einer
> Auflistung zugreifen will?

Das 3. Element hat in C den Index 2. Um also die 8 Elemente mit den
Indizes 2 bis 9 zu kopieren, schreibst du:

1
  memcpy(ziel, array+2, 8*sizeof array[0]);

Falls du kein Freund von Zeigerarithmetik bist, kannst du statt array+2
auch &array[2] schreiben, was exakt dasselbe ist.

Das funktioniert unabhängig vom Elementyp des Arrays. Egal, ob array so

1
  char array[10];

oder so

1
  struct mystruct array[10];

oder so

1
  double array[10][3];

definiert ist, es werden immer die gewünschten Daten kopiert.

von Besucher (Gast)


Lesenswert?

Ehrlich gesagt würde ich mir in so einem Fall eine eigene Kopierfunktion 
schreiben (gerne auch in inline-assembler). Sind auch nur ein paar 
Zeilen, man kann es den gegebenen Erfordernissen anpassen, man weiss 
genau was wohin kopiert wird, und weniger performant als das 
standard-memcpy wird's kaum werden.

von memcpy (Gast)


Lesenswert?

Besucher schrieb:
> Ehrlich gesagt würde ich mir in so einem Fall eine eigene Kopierfunktion
> schreiben (gerne auch in inline-assembler). Sind auch nur ein paar
> Zeilen, man kann es den gegebenen Erfordernissen anpassen, man weiss
> genau was wohin kopiert wird, und weniger performant als das
> standard-memcpy wird's kaum werden.

Das mag so sein, aber was an:
1
  memcpy(ziel, array+2, 8*sizeof array[0]);

ist lang, entspricht nicht den Erfordernissen oder lässt offen, was 
wohin kopiert wird?

Das Rad ist bisher durch keine seiner Neu-Erfindungungen wesentlich 
runder geworden. :-)

von Fpgakuechle K. (Gast)


Lesenswert?

ArduStemmi schrieb:

> umstricken kann. Die Daten sind zum Teil schon im EEPROM und müssten
> auch dort umgestrickt werden.
>
> Aber wie lautet den der memcpy Befehl..

Funktioniert memcpy() auch für EEPROM? Der hat doch seine eigenen 
Zugriffsmechanismus:
"The access between the EEPROM and the CPU is described in the 
following, specifying the EEPROM Address Registers, the EEPROM Data 
Register, and the EEPROM Control Register" (Datenblatt S.19)

Wann nimmt man:
http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__eeprom.html

von Fpgakuechle K. (Gast)


Lesenswert?

Noch ein Aspekt der Beachtung verdient: 16bit versus 8bit transfers.

Der µC kann beides. Falls der vector aus 8bit breiten elementen besteht, 
könnte man das kopieren beschleunigenen wenn man die Kopierschleife mit 
16 bit transfers betreibt. Dazu muss man das erste und letzte byte ggf. 
extra behandeln da ggf. missaligned. Beherscht das memcpy()?

von Rolf M. (rmagnus)


Lesenswert?

Besucher schrieb:
> Ehrlich gesagt würde ich mir in so einem Fall eine eigene Kopierfunktion
> schreiben (gerne auch in inline-assembler). Sind auch nur ein paar
> Zeilen, man kann es den gegebenen Erfordernissen anpassen, man weiss
> genau was wohin kopiert wird, und weniger performant als das
> standard-memcpy wird's kaum werden.

Auf einem AVR, wo's im Prinzip nur einen Weg gibt, um einen 
Speicherblock zu kopieren, mag das stimmen. Allgemeingültig ist die 
Aussage aber nicht. In der Regel hat man keinerlei Vorteil davon, statt 
memcpy() eine handgestrickte Schleife zu machen. Und in Assembler würde 
ich das schon gar nicht machen, außer wenn es einen ganz konkreten Grund 
gäbe, warum das Programm dadurch signifikant schneller würde (z.B. weil 
man sehr große Datenblöcke kopieren muss und das verfügbare memcpy einen 
ganz besonders effizienzen Weg nicht nutzt).

Fpga K. schrieb:
> Noch ein Aspekt der Beachtung verdient: 16bit versus 8bit transfers.
>
> Der µC kann beides.

Wie das? Der RAM ist doch nur 8-bittig angebunden.

Fpga K. schrieb:
> Funktioniert memcpy() auch für EEPROM?

Nein. Du hast es doch selber verlinkt. Wenn du Daten aus dem EEPROM ins 
RAM kopieren willst, nimmst du eepropm_read_block() statt memcpy().

von Fpgakuechle K. (Gast)


Lesenswert?

Rolf M. schrieb:
> Fpga K. schrieb:
>> Noch ein Aspekt der Beachtung verdient: 16bit versus 8bit transfers.
>>
>> Der µC kann beides.
>
> Wie das? Der RAM ist doch nur 8-bittig angebunden.

Hm, da hab ich MOVW und SPM fälschlicherweise mit dem SRAM in Verbindung 
gebracht.

> Fpga K. schrieb:
>> Funktioniert memcpy() auch für EEPROM?
>
> Nein. Du hast es doch selber verlinkt. Wenn du Daten aus dem EEPROM ins
> RAM kopieren willst, nimmst du eepropm_read_block() statt memcpy().

Ja, dann nützt dem TO memcpy wenig weil er EEPROM-Daten kopieren will.

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.