Forum: Mikrocontroller und Digitale Elektronik C++ Array um eine Stelle verschieben


von Stefan H. (stefan_h143)


Lesenswert?

Hallo zusammen,
Ich versuche gerade die Werte in einem Array, bzw. drei Arrays, um 
jeweils eine Index-Stelle weiter zu schieben.

Soll heißen, ich schreibe in den Index 0 bei jedem Durchlaufes des 
Programmes irgendwas hinein und dann sollen die alten Werte jeweils um 
einen Platz weiter geschrieben werden. Der Wert, der hinten quasi raus 
fällt ist egal.
Das Array hat 42 index-Stellen.

momentan versuche ich das so:
1
//Schieberegister weiter schieben
2
for (int i=41; i<1; i--){
3
  reihe_rot [i] = reihe_rot [i-1];
4
  reihe_gruen [i] = reihe_gruen [i-1];
5
  reihe_blau [i] = reihe_blau [i-1];
6
}


Könnt ihr mir sagen, warum das nicht funktioniert?
Gruß
Stefan

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Stefan H. schrieb:
> for (int i=41; i<1; i--){

Du setzt i auf 41 und fragst dann ob es kleiner 1 ist. Das ist nicht der 
Fall. Benutze size_t für Array Indices, nicht int.

von IUnknown (Gast)


Lesenswert?

i<1
ist die falsche Laufbedingung
versuch mal lieber:
i>0
oder noch kürzer, da alles != 0 als wahr angesehen wird:
i

von Stefan H. (stefan_h143)


Lesenswert?

IUnknown schrieb:
> i<1
> ist die falsche Laufbedingung
> versuch mal lieber:
> i>0
> oder noch kürzer, da alles != 0 als wahr angesehen wird:
> i

Mann mann mann... Kopf gegen Wand Moment... Danke :D

Es ist zu spät, ich sollte eher schlafen... Danke, jetzt funktioniert es 
:)

von Stefan H. (stefan_h143)


Lesenswert?

Dr. Sommer schrieb:
> Benutze size_t für Array Indices, nicht int.

Öhm okay, was bringt das für Vorteile? hab bis jetzt immer Int genommen

von Dr. Sommer (Gast)


Lesenswert?

Stefan H. schrieb:
> Öhm okay, was bringt das für Vorteile?

Auf manchen Plattformen wie AMD64 reicht int nicht aus für die mögliche 
Größe von Arrays. Außerdem ist es sinnlos einen vorzeichenbehafteten 
Integer für etwas zu nehmen, was nie negativ wird.

Immer int zu nehmen macht man in Java, aber nicht C oder C++ :)

von Lks (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Stefan H. schrieb:
>> Öhm okay, was bringt das für Vorteile?
>
> Auf manchen Plattformen wie AMD64 reicht int nicht aus für die mögliche
> Größe von Arrays. Außerdem ist es sinnlos einen vorzeichenbehafteten
> Integer für etwas zu nehmen, was nie negativ wird.
>
> Immer int zu nehmen macht man in Java, aber nicht C oder C++ :)

Ein ganz klares "kommt drauf an". size_t scheint erst einmal die 
logische wahl im C/C++ Kontext zu sein, allerdings sind 
vorzeichenbehaftete Indizes effizienter umgesetzt (in Hardware).

von Micha (nichtgast)


Lesenswert?

Moin,

w're es nicht besser, nur den Schreibezeiger "rotieren" zu lassen 
anstatt immer alle Daten unnötig in der Gegend umzukopieren?

Also wenn Daten reinkommen einfach die nächste Stelle im Array 
beschreiben und wenn das Ende erreicht ist, einfach von vorne wieder 
anfangen. Gibt das gleiche Verhalten nach außen und du musst nicht immer 
alle Werte umkopieren.

Das selbe gilt dann natürlich auch für den Lesezeiger.

von M. K. (sylaina)


Lesenswert?

Keiner N. schrieb:
> w're es nicht besser, nur den Schreibezeiger "rotieren" zu lassen
> anstatt immer alle Daten unnötig in der Gegend umzukopieren?

Das hab ich mir auch gesagt. Würde hier auch nur den entsprechenden 
Schreibzeiger rotieren lassen statt immer das komplette Array 
umzukopieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Stefan H. schrieb:
>> for (int i=41; i<1; i--){
>
> Du setzt i auf 41 und fragst dann ob es kleiner 1 ist. Das ist nicht der
> Fall. Benutze size_t für Array Indices, nicht int.

Auch das nicht, sondern C::size_type (C ist der Typ des Containers). Das 
ist zwar bei der stdlibc++ immer size_t, da es aber hier um µC geht, hat 
man es oft nicht mit der stdlibc++ zu tun, sondern mit speziell 
adaptierten Varianten. Da könnte C::size_type auch z.B. ein uint8_t oder 
uint16_t sein.

von Stefan H. (stefan_h143)


Lesenswert?

Danke schon mal für eure Antworten :)
Ich bin noch relativ neu in der ganzen Geschichte, daher jetzt mal eine 
dumme Frage:
Was meint ihr mit Lesezeiger und Schreibezeiger rotieren lassen?

Ich habe nur einen kleinen Ausschnitt aus meiner Funktion gepostet, ich 
könnte später auch noch mal den kompletten Ausschnitt rein stellen. (hab 
ich gerade nicht da)

Ich hatte hier :
https://www.mikrocontroller.net/articles/Plattformunabh%C3%A4ngige_Programmierung_in_C

gelesen, dass int den Vorteil bietet, dass es das Format ist, welches 
der prozessor am schnellsten bearbeiten kann. Daher hab ich immer int 
genommen.

Ist das nicht so, bzw. hab ich das falsch vestanden?

Dr. Sommer schrieb:
> eicht int nicht aus für die mögliche
> Größe von Arrays.

also unsigned int? bzw gibt es dann einen Unterschied zu unit16_t?


Gruß
Stefan

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Stefan H. schrieb:
> also unsigned int?

Reicht ggf. auch nicht. Auf AMD64 können Arrays 2^64 Elemente enthalten, 
aber (unsigned) int ist typischerweise nur 32bit groß, kann also nur 
2^32 Elemente adressieren.

Stefan H. schrieb:
> bzw gibt es dann einen Unterschied zu unit16_t?

uint16_t ist was völlig anderes, eben nur 16 bit groß. Ist zu klein für 
Arrays auf x86 und AMD64, und ARM, und eigentlich nur ausreichend auf 
AVR.

Am Einfachsten ist es immer size_t zu nehmen, das funktioniert immer. 
Einen anderen Typ sollte man nur nehmen wenn man sich genau überlegt hat 
ob er immer ausreicht.


Stefan H. schrieb:
> Was meint ihr mit Lesezeiger und Schreibezeiger rotieren lassen?
Such mal nach FIFO...

Wilhelm M. schrieb:
> da es aber hier um µC geht, hat
> man es oft nicht mit der stdlibc++ zu tun, sondern mit speziell
> adaptierten Varianten.
Kennst du eine Bibliothek bei der das so ist? Und hier geht es um 
Arrays, nicht Container.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:

> Wilhelm M. schrieb:
>> da es aber hier um µC geht, hat
>> man es oft nicht mit der stdlibc++ zu tun, sondern mit speziell
>> adaptierten Varianten.
> Kennst du eine Bibliothek bei der das so ist?

Ja, meine eigene ;-)

Im Ernst: die Väter der stdlibc++ haben sich schon etwas dabei gedacht. 
Es handelt sich um eine Art statisches Reflection-API. Der Container 
informiert den generischen Code über den size_type. Dadurch ist es 
möglich eigene Container zu schreiben (so wie bei meiner Variante) mit 
angepasstem size_type. Und dann funktioniert der Code immer richtig 
und(!) optimal.

Man ist i.Ü. gut beraten, dieses statische Reflection-API für eigene 
Container einzuhalten, damit dann auch die Algorithmen wieder so 
funktionieren wie sie sollen.

> Und hier geht es um
> Arrays, nicht Container.

Genau, std::array könnte man vermuten ... ich nichts con C-Style-Arrays 
gelesen.

von Stefan H. (stefan_h143)


Lesenswert?

Dr. Sommer schrieb:
> ausreichend auf
> AVR.

Ah okay.
Ja gut, das ist dann wohl ein Missverständniss :) Es geht bei mir ja 
explizit um einen AVR.

von Dr. Sommer (Gast)


Lesenswert?

Stefan H. schrieb:
> Ja gut, das ist dann wohl ein Missverständniss :) Es geht bei mir ja
> explizit um einen AVR.

Da kannste trotzdem size_t nehmen, das ist da das gleiche wie uint16_t. 
Dafür macht der Code keine Probleme, solltest du ihn jemals z.B. auf 
Cortex-M portieren...

Wilhelm M. schrieb:
> Man ist i.Ü. gut beraten, dieses statische Reflection-API für eigene
> Container einzuhalten,
Schon, aber verschiedene Index-Typen für verschiedene Container zu 
nutzen führt schnell zu einem ziemlichen Chaos, weil so ein Index ja oft 
auch ausgetauscht werden muss. Da ist es einfacher immer size_t zu 
nehmen und das nur zu optimieren wenn das Programm tatsächlich deswegen 
zu langsam ist (eh eher unwahrscheinlich).

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:

> Wilhelm M. schrieb:
>> Man ist i.Ü. gut beraten, dieses statische Reflection-API für eigene
>> Container einzuhalten,
> Schon, aber verschiedene Index-Typen für verschiedene Container zu
> nutzen führt schnell zu einem ziemlichen Chaos, weil so ein Index ja oft
> auch ausgetauscht werden muss.

Ganz und gar nicht: es macht ggf. das Problem sichtbar! Vor allem, wenn 
man es so gestaltet, dass die Index-Typen nicht implizit, sondern nur 
explizit ineinander konvertierbar sind.
Denn es macht ja nun wenig Sinn, für einen Container, der nur 256 
Elemente fassen kann, einen Index-Typ mit 16-Bit zu verwenden.

von Dr. Sommer (Gast)


Lesenswert?

Wie würdest du denn dann z.B. folgenden (recht sinnfreien) Algorithmus 
so bauen, dass er auch dann noch funktioniert, wenn die beiden Container 
unterschiedliche Index-Typen haben?
1
#include <iostream>
2
#include <algorithm>
3
#include <cstddef>
4
#include <vector>
5
#include <array>
6
7
template <typename C1, typename C2>
8
void test (C1& c1, const C2& c2, size_t off1, size_t off2) {
9
  size_t count = std::min<size_t> (c1.size () - off1, c2.size () - off2);
10
  
11
  for (size_t i = 0; i < count; ++i) {
12
    std::cout << "Kopiere Element " << i << std::endl;
13
    c1 [i+off1] = c2[i+off2];
14
  }
15
}
16
17
int main () {
18
  std::vector<int> c1 (33);
19
  std::array<int, 42> c2;
20
  
21
  test (c1, c2, 3, 7);
22
}
Ich vermute das gibt eine Menge lustiger casts und Fallunterscheidungen; 
ziemlich schwierig es korrekt hinzubekommen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Erster Q-n-D-Ansatz:
hier würde ich pessimistisch vorgehen: das Ganze macht nur Sinn, wenn 
die generierten Indizes innerhalb der durch die Indextypen vorgegeben 
Wertebereiche liegen.
1
template<typename T1, typename T2>
2
struct Smaller{
3
    using type = typename std::conditional<std::numeric_limits<T1>::max() <= std::numeric_limits<T2>::max(), T1, T2>::type;
4
};
5
6
template<typename T>
7
void showType() {
8
    std::cout << __PRETTY_FUNCTION__ << '\n';
9
}
10
11
template <typename C1, typename C2>
12
void test (C1& c1, const C2& c2, size_t off1, size_t off2) {
13
    
14
    using index1_type = typename C1::size_type;
15
    using index2_type = typename C2::size_type;
16
    using index_type = typename Smaller<index1_type, index2_type>::type;
17
    
18
    showType<index_type>();
19
    
20
    size_t count = std::min<size_t> (c1.size () - off1, c2.size () - off2);
21
    
22
    assert((count + off1) <= std::numeric_limits<index_type>::max());
23
    assert((count + off2) <= std::numeric_limits<index_type>::max());
24
    
25
    for (index_type i = 0; i < count; ++i) {
26
        std::cout << "Kopiere Element " << int(i) << std::endl;
27
        c1 [index1_type{i+off1}] = c2[index2_type{i+off2}];
28
    }
29
}

von Dr. Sommer (Gast)


Lesenswert?

Wilhelm M. schrieb:
> <std::numeric_limits<T1>::max() <= std::numeric_limits<T2>::max()

Das klappt eventuell nicht wenn es keinen Typ gibt der groß genug ist um 
die Bereiche von T1 und T2 abzudecken.

Wilhelm M. schrieb:
> void test (C1& c1, const C2& c2, size_t off1, size_t off2) {
Hier doch wieder size_t?

Wilhelm M. schrieb:
> size_t count = std::min<size_t> (c1.size () - off1, c2.size () -
> off2);
Der Vergleich soll dann doch auf size_t durchgeführt werden? Ist size_t 
nicht eventuell zu groß für "count"?

Wilhelm M. schrieb:
> for (index_type i = 0; i < count; ++i) {

Wenn index_type kleiner als size_t ist, macht man hier dann ständig 
unnötige Vergleiche via size_t

Wilhelm M. schrieb:
> std::cout << "Kopiere Element " << int(i) << std::endl;
Was wenn "i" größer als "int" ist?

Wilhelm M. schrieb:
> c1 [index1_type{i+off1}] = c2[index2_type{i+off2}];
Das gibt ggf. Compiler-Warnungen wegen Integer Promotion

von Jobst Q. (joquis)


Lesenswert?

Stefan H. schrieb:
> Ich bin noch relativ neu in der ganzen Geschichte, daher jetzt mal eine
> dumme Frage:
> Was meint ihr mit Lesezeiger und Schreibezeiger rotieren lassen?

Dann wird das ein Ringpuffer oder FIFO. Lies dir das mal durch :

https://www.mikrocontroller.net/articles/FIFO

von Wilhelm M. (wimalopaan)


Lesenswert?

Mein Post war auch mehr als Ideengeber gedacht als fertiger Code ....

Dr. Sommer schrieb:
> Wilhelm M. schrieb:
>> <std::numeric_limits<T1>::max() <= std::numeric_limits<T2>::max()
>
> Das klappt eventuell nicht wenn es keinen Typ gibt der groß genug ist um
> die Bereiche von T1 und T2 abzudecken.

s.u. im Code

>
> Wilhelm M. schrieb:
>> void test (C1& c1, const C2& c2, size_t off1, size_t off2) {
> Hier doch wieder size_t?

Das war nur Nachlässigkeit (s.u.)

>
> Wilhelm M. schrieb:
>> size_t count = std::min<size_t> (c1.size () - off1, c2.size () -
>> off2);
> Der Vergleich soll dann doch auf size_t durchgeführt werden? Ist size_t
> nicht eventuell zu groß für "count"?

s.u.

>
> Wilhelm M. schrieb:
>> for (index_type i = 0; i < count; ++i) {

s.u.

>
> Wenn index_type kleiner als size_t ist, macht man hier dann ständig
> unnötige Vergleiche via size_t
>
> Wilhelm M. schrieb:
>> std::cout << "Kopiere Element " << int(i) << std::endl;
> Was wenn "i" größer als "int" ist?

War nur ggf. wegen uint8_t als index_type, dass würde sonst als char 
ausgegeben, s.u.

>
> Wilhelm M. schrieb:
>> c1 [index1_type{i+off1}] = c2[index2_type{i+off2}];
> Das gibt ggf. Compiler-Warnungen wegen Integer Promotion

besser gesagt wegen narrowing. Auch dazu s.u.
1
template<typename T1, typename T2>
2
struct Smaller {
3
    using type = typename std::conditional<std::numeric_limits<T1>::max() <= std::numeric_limits<T2>::max(), T1, T2>::type;
4
};
5
template<typename T1, typename T2>
6
struct Bigger {
7
    using type = typename std::conditional<std::numeric_limits<T1>::max() <= std::numeric_limits<T2>::max(), T2, T1>::type;
8
};
9
10
template<typename T>
11
void showType() {
12
    std::cout << __PRETTY_FUNCTION__ << '\n';
13
}
14
15
template <typename C1, typename C2>
16
void test (C1& c1, const C2& c2, typename C1::size_type off1, typename C2::size_type off2) {
17
    using index1_type = typename C1::size_type;
18
    using index2_type = typename C2::size_type;
19
    static_assert(std::is_unsigned<index1_type>::value);
20
    static_assert(std::is_unsigned<index2_type>::value);
21
    using index_type = typename Smaller<index1_type, index2_type>::type;
22
    using enclosing_type = typename Bigger<index1_type, index2_type>::type;
23
    
24
    assert(off1 <= c1.size());
25
    assert(off2 <= c2.size());
26
    
27
#ifndef NDEBUG
28
    showType<index_type>();
29
    showType<enclosing_type>();
30
#endif
31
    
32
    enclosing_type count = std::min(enclosing_type(c1.size() - off1), 
33
                                    enclosing_type(c2.size() - off2));
34
    
35
    assert(count <= std::numeric_limits<index_type>::max());
36
    assert((count + off1) <= std::numeric_limits<index_type>::max());
37
    assert((count + off2) <= std::numeric_limits<index_type>::max());
38
    assert((count + off1) <= c1.size());
39
    assert((count + off2) <= c2.size());
40
    
41
    for (index_type i = 0; i < index_type(count); ++i) {
42
        std::cout << "Kopiere Element " << std::to_string(i) << std::endl;
43
        c1[index1_type(i + off1)] = c2[index2_type(i + off2)];
44
    }
45
}

Einige Laufzeit-Zusicherungen sind hier nur Testing-Comments. Ist auch 
alles nur schnell hingeschrieben, keine Ahnung, ob ich an alles gedacht 
habe ;-)

von M. K. (sylaina)


Lesenswert?

Stefan H. schrieb:
> Danke schon mal für eure Antworten :)
> Ich bin noch relativ neu in der ganzen Geschichte, daher jetzt mal eine
> dumme Frage:
> Was meint ihr mit Lesezeiger und Schreibezeiger rotieren lassen?
> ...

Eigentlich willst du einen Ringpuffer aufbauen, dazu gibt es hier ein 
schönes Beispiel mit Lösungsansätzen für verschiedene Sprachen, u.a. C:

https://www.programmieraufgaben.ch/aufgabe/ringpuffer-mit-arrays/yui8z5du

von Egon N. (egon2321)


Lesenswert?

http://www.cplusplus.com/reference/stl/


Container adaptors:

stack
    LIFO stack (class template )

queue
    FIFO queue (class template )

priority_queue
    Priority queue (class template )


Wieso nicht einfach einen fertigen Container dafür benutzen?

M. K. schrieb:
> Eigentlich willst du einen Ringpuffer aufbauen, dazu gibt es hier ein
> schönes Beispiel mit Lösungsansätzen für verschiedene Sprachen, u.a. C:
>
> https://www.programmieraufgaben.ch/aufgabe/ringpuffer-mit-arrays/yui8z5du

Das soll doch ein schlechter Scherz sein, oder?

von Wilhelm M. (wimalopaan)


Lesenswert?

Egon N. schrieb:
> http://www.cplusplus.com/reference/stl/
> Container adaptors:
>
> stack
>     LIFO stack (class template )
>
> queue
>     FIFO queue (class template )
>
> priority_queue
>     Priority queue (class template )
>
>
> Wieso nicht einfach einen fertigen Container dafür benutzen?

Es ist gut, wenn man die Threads auch mal liest: es geht dem TO um AVR, 
da gibt es keine fertige stdlibc++ und ich glaube auch nicht, dass der 
TO sie sich selbst schreibt ;-)

von R. M. (n_a_n)


Lesenswert?

In C++ einzelne Bits shiften, geht ganz komfortabel mit bitset.
Aber ich weis nicht ob es auf einem AVR so performant ist,
war damals Software für PC.
1
void Utils::shiftVucLeftOrRight (vector<unsigned char> &v , int shifts, bool left)
2
{
3
  
4
  bitset<160*8> bs; // large enough for this usecase 
5
6
  bs.reset();
7
8
  int vlen = v.size();
9
10
  for (int bytes = 0; bytes < vlen; bytes ++)
11
  {
12
    for (int bits = 0; bits < 8; bits ++)
13
    {
14
      unsigned char t1 = v[vlen - 1 - bytes];
15
      if ( t1 & (1<<bits))
16
        bs.set(8 * bytes + bits,1);
17
    }
18
19
  }
20
  
21
  if (left)
22
    bs <<= shifts;
23
  else
24
    bs >>= shifts;
25
  
26
  for (int bytes = 0; bytes < vlen; bytes ++)
27
  {
28
    unsigned char t1 = 0x00;
29
    for (int bits = 0; bits < 8; bits ++)
30
    {
31
      if(bs.test(8 * bytes + bits))
32
      {
33
        t1 |= (1 << bits);
34
      }
35
    }
36
    v[vlen - 1 - bytes] = t1;
37
38
  }
39
}

von Egon N. (egon2321)


Lesenswert?

Wilhelm M. schrieb:
> Es ist gut, wenn man die Threads auch mal liest: es geht dem TO um AVR,
> da gibt es keine fertige stdlibc++ und ich glaube auch nicht, dass der
> TO sie sich selbst schreibt ;-)

Man kann sich durchaus von der Bibliothek inspirieren lassen. Man muss 
nicht die ganze Lib implementieren, aber die Ausführungen sind in der 
Regel sehr gut.

Zudem kann man es als Anreiz verstehen sich mal Cortex-M anzuschauen, 
denn da gibt es eine stdlib++.

von M. K. (sylaina)


Lesenswert?

Egon N. schrieb:
> Das soll doch ein schlechter Scherz sein, oder?

Warum?

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.