Größe eines Arrays als Funktionsparameter ermitteln

void setup() {
  Serial.begin(9600);

  int myInts[] = {1, 50, 500, 700};
  Serial.println(sizeof(myInts) / sizeof(int));

  Serial.println(ImBereich(55, myInts));
}

void loop() {

}

byte ImBereich(int x, const int Bereichsgrenzen[]) {
  byte i = 0;
  Serial.println(sizeof(Bereichsgrenzen) / sizeof(int), DEC);
  Serial.println("===");

  return 17;
}

Wie ermittle ich die Größe des übergebenen Arrays richtig?

Vielen Dank für eure Hilfe

Ich verstehe dich nicht?

Was soll mit der 55 passieren?

constexpr size_t arrayCellCount(const auto &array)
{
  return sizeof(array)/sizeof(array[0]);
}

void setup() {
  Serial.begin(9600);

  int myInts[] = {1, 50, 500, 700};
  Serial.println(arrayCellCount(myInts));
}

void loop() 
{

}

Das ist der Grund weshalb ich diese vereinfachte Schreibweise überhaupt nicht mag. Arrays sollte man normalerweise als Zeiger übergeben. Dann sieht man auch sofort wieso sizeof() nicht funktionieren kann. Die Größe kann man dann als extra Parameter übergeben. Das ist Standard in C:

void func(int* array, unsigned int length)
{
 Serial.println(length);
}

void setup()
{
  Serial.begin(9600);
 
  int array[10];
  func(array, sizeof(array) / sizeof(array[0]));
}

In C++ gibt es aber auch Referenzen. Und bei einer Referenz auf ein Array geht auch sizeof():

void func(int(&array)[10])
{
   Serial.println(sizeof(array) / sizeof(array[0]));
}

void setup()
{
  Serial.begin(9600);
 
  int array[10];
  func(array);
}

Geht aber dann nur mit Arrays dieser Größe

Oder wenn du beliebige Arrays übergeben willst, mit einem Template:

template<typename T, unsigned int N>
void func(T(&array)[N])
{
  Serial.println(N);
}

void setup()
{
  Serial.begin(9600);

  int array[10];
  func(array);
}

Erstmal vielen Dank für eure Antworten.

constexpr size_t arrayCellCount(const auto &array)
{
  return sizeof(array)/sizeof(array[0]);
}

void setup() {
  Serial.begin(9600);

  int myInts[] = {1, 50, 500, 700};
  Serial.println(arrayCellCount(myInts));
}

void loop()
{

}

liefert bei mir:

t5:1: error: 'constexprsize_t' does not name a type

 constexpr size_t arrayCellCount(const auto &array)

 ^

D:\arduino\Sketch\t5\t5.ino:1:33: warning: use of 'auto' in parameter declaration only available with -std=c++1y or -std=gnu++1y

 constexpr size_t arrayCellCount(const auto &array)

                                 ^

exit status 1
'constexprsize_t' does not name a type

Habe die erste Zeile mal zu int arrayCellCount(const auto &array) geändert, dann lief es bei mir.

Wenn ich euchrichtig verstanden habe, ist das der Weg als Referenz den Serenifly auch beschreibt?

Die 55 ist nur ein Beispielwert. (Meine Funktion soll mir die Position in einem Bereich zurückgeben. Ich übergebe neben dem Wert ein Array mit den Bereichsgrenzen. Soll mir viele if, elseif ersparen.)

==========

Die Größe kann man dann als extra Parameter übergeben. Das ist Standard in C:

Ok, hatte ich zwar schon mal in anderen Beispielen gesehen und mich gewundert, warum man das übergibt und nicht ermittelt, aber wenn dass in c++ Standard ist, weiß ich jetzt mehr.

In C++ gibt es aber auch Referenzen. Und bei einer Referenz auf ein Array geht auch sizeof():
...
Geht aber dann nur mit Arrays dieser Größe

Wenn ich vorher die Größe festlegen muss, hilft mir das nichts, da ich die gerne variabel hätte.

Die Variante mit dem Template sieht interessant aus, aber ich verstehe sie nicht, da ich noch nie mit Templates zu tun hatte. Ich werde dann jetzt auch den Standard-Weg verwenden, ist ja nicht ohne Grund Standard :wink: und mich evtl. später mal mit den Templates beschäftigen.

Vielen Dank für die Hilfe.
Viele Grüße Frank

Ok, hatte ich zwar schon mal in anderen Beispielen gesehen und mich gewundert, warum man das übergibt und nicht ermittelt, aber wenn dass in c++ Standard ist, weiß ich jetzt mehr.

Das kommt aus C. Nicht aus C++. Das sind zwei verschiedene Sprachen

In C++ verwendet man Arrays heute eher weniger und nimmt lieber Container wie Vektoren. Die STL bietet mit std::array auch einen Container für klassische Arrays an der nicht in einen Zeiger zerfällt. Aber das gibt es auf den AVR Arduinos nicht.

Wenn ich euchrichtig verstanden habe, ist das der Weg als Referenz den Serenifly auch beschreibt?

Das ist eine Hilfsfunktion um die Größe zu berechnen. Dann muss man die Größe nicht in der eigentlichen Funktion behandeln. Sei es als Parameter oder dass man sie an der Stelle erst ausrechnet

Den Fehler bekommst du glaube weil das so erst mit C++14 geht. Und dafür fehlt bei dir der Compiler Switch. Oder es ist als GCC Extension erlaubt (z.B. Concepts Lite, was erst Teil von C++17 ist). Mit dem neustens in der IDE verfügbaren Compiler und der entsprechenden Option aktiviert sollte das auch kompilieren.

Das Entfernen von constexpr an der Stelle behebt zwar den Fehler, aber der Code macht eventuell was anderes.
Und int als Datentyp ist an der Stelle dämlich. Seit wann kann eine Größe negativ sein?

Templates sind Code Generatoren. Man gibt generische Typen an die vom Compiler dann damit ersetzt werden was eigentlich vorhanden ist. Das hat auch zur Folge dass zwei Funktionen generiert werden wenn du da zwei verschiedene Arrays übergibst.

Habe die erste Zeile mal zu int arrayCellCount(const auto &array) geändert, dann lief es bei mir.

Ich verwende Arduino IDE 1.8.5, kompiliert für einen UNO

Compiler Parameter ist der Arduino Standard: -std=gnu++11

Wenn ich euchrichtig verstanden habe, ist das der Weg als Referenz den Serenifly auch beschreibt?

Durchaus.
Ich nenne es mal meinen "bevorzugten Weg".

Ich verwende Arduino IDE 1.8.5

OK, ich habe noch 1.6.8; dabei ist die Option beim Start nach Updates suchen angehakt.
Ich sollte mal ein manuelles Update machen.

Danke und viele Grüße

Frank

dabei ist die Option beim Start nach Updates suchen angehakt.

Damit werden nur Libraries und Boarddefinitionen verarbeitet.

Das gilt nicht für die IDE selber.

OK, noch etwas gelernt.

Update ist gemacht, Funktion läuft.

Vielen Dank für die Hilfe.

Übrigens...
auto Funktionsparameter werden nicht von jedem Kompiler verarbeitet.
Darum hagelt es bei dir auch eine Warnung.

z.B. beim ESP geht es (noch) nicht.

// fuer moderne Kompiler C++11 und neuer
constexpr size_t arrayCellCount(const auto &array)
{
  return sizeof(array)/sizeof(array[0]);
}

// ----

// fuer alte C++ Kompiler  
#define ARRAYCELLCOUNT(array) (sizeof(array)/sizeof(array[0]))

// ----

// fuer mittelalte Kompiler (auch ESP)
template<typename DatenType> constexpr size_t ArrayCellCount(const DatenType &array)
{
  return sizeof(array)/sizeof(array[0]);
}

// ---



void setup() 
{
  Serial.begin(9600);

  int myInts[] = {1, 50, 500, 700};

  
  Serial.println(arrayCellCount(myInts));
  Serial.println(ArrayCellCount(myInts));
  Serial.println(ARRAYCELLCOUNT(myInts));

}


void loop() 
{

}

Allen 3 Varianten ist gemein, dass die Berechnung zur Kompilezeit erfolgt.
Der Array Type/Größe muss also auch schon zur Kompilezeit fest stehen.