Forum: PC-Programmierung C sizeof Funktion in main vs in Funktion


von Marco D. (schoggo1992)


Lesenswert?

Guten Abend, anbei ein Code zur Berechnung des minimalen und maximalen 
Wertes eines Arrays. Ich möchte gerne das Array durchlaufen und als 
Abbruchbediungung wollte ich den Wert bla: sizeof(zahlen)/sizeof(int) 
verwenden. Im main-Programm habe ich es nur zur Überprüfung des Wertes 
aufgerufen. bla ergibt aber in der main den Wert 4 und in der Funktion 
den Wert 1, wieso ?

#include "pch.h"
#include <iostream>

double MinMaxDurch(int zahlen[]) {
  int min = zahlen[0];
  int max = zahlen[0];
  int summe = 0;
  int bla = sizeof(zahlen)/sizeof(int);
  for (int i = 0; i < bla; i++) {
    if (zahlen[i] < min) min = zahlen[i];
    if (zahlen[i] > max) max = zahlen[i];
    summe += zahlen[i];
  }
  printf("Minimum: %d ", min);
  printf("Maximum: %d ", max);

  return (float)summe/(float)sizeof(zahlen);

  return 0;
}

int main()
{
  int zahlen[] = {3,7,5,10,122};
  int bla = sizeof(zahlen)/sizeof(int);
  MinMaxDurch(zahlen);
  return 0;
}

von Johannes S. (Gast)


Lesenswert?

weil das Argument 'int zahlen[]' ein einfacher Zeiger ist und damit 
keine Grösseninfo übertragen wird. Das musst du mit einem zweiten 
Argument 'int AnzzahlElemente' selber hinzufügen.
Oder mit containern der std lib arbeiten.

von Rolf M. (rmagnus)


Lesenswert?

Marco D. schrieb:
> Im main-Programm habe ich es nur zur Überprüfung des Wertes
> aufgerufen. bla ergibt aber in der main den Wert 4 und in der Funktion
> den Wert 1, wieso ?

int zahlen[] ist in einer Parameterliste äquivalent zu int * zahlen, 
also ein Zeiger auf einen int. sizeof zahlen gibt dir daher die Größe 
eines Zeigers zurück.

von Marco D. (schoggo1992)


Lesenswert?

Ok, danke euch. Sehr einleuchtend.

von (prx) A. K. (prx)


Lesenswert?

Marco D. schrieb:
> double MinMaxDurch(int zahlen[]) {

Schreib das im Kontext von Funktionsparametern lieber als
  double MinMaxDurch(int *zahlen) {

Ist sowieso exakt gleich, verarscht dich aber nicht.

von Markus E. (markus_e176)


Lesenswert?

Aber wieso kommen dann unterschiedliche Ergebnisse raus?
Zahlen[] bzw. Int* müsste doch immer gleich groß sein?

von (prx) A. K. (prx)


Lesenswert?

Markus E. schrieb:
> Aber wieso kommen dann unterschiedliche Ergebnisse raus?
> Zahlen[] bzw. Int* müsste doch immer gleich groß sein?

In einer Parameterdeklaration ist das identisch. Aber nur da. An anderer 
Stelle sind das zwei Paar Stiefel. Das hier ist keine 
Parameterdeklaration:
  int zahlen[] = {3,7,5,10,122};

Ich fand es keine gute Idee, dass C die Leute verarscht, indem in 
Parameterdeklaration daraus implizit ein Pointer wird.

von Theor (Gast)


Lesenswert?

Entscheidend ist dass in main die Grösse des Arrays bekannt ist. In der 
Parameterliste aber nicht, da die Grössenangabe fehlt.

In main kann also sizeof die Grösse des Arrays ermitteln. In der 
Funktion aber nur die Grösse des Zeigers. An dieser Stelle ist int *x 
und int x [] äquivalent. Wäre hingegen die Grösse ausdrücklich angegeben 
worden int x [17] dann würde sizeof diese Information verwenden.

Im C-Standard ist das ausführlich erklärt.

Bemerkung:
Etwas irreführend kann die irrige Annahme sein, dass der Compiler den 
gesamten Kontext berücksichtigt. Ein menschlicher Leser, weiss ja, wie 
lang das Array ist. Der Compiler betrachtet aber die Funktionen einzeln 
ohne ihren Kontext.

von (prx) A. K. (prx)


Lesenswert?

Theor schrieb:
> Wäre hingegen die Grösse ausdrücklich angegeben
> worden int x [17] dann würde sizeof diese Information verwenden.

Bei einem solcherart deklarierten Parameter?

von tictactoe (Gast)


Lesenswert?

Theor schrieb:
> Wäre hingegen die Grösse ausdrücklich angegeben
> worden int x [17] dann würde sizeof diese Information verwenden.

Ganz und gar nicht. Ein solcher Art Parameter wäre ebenfalls äquivalent 
zu int* x; die 17 an dieser Stelle ist nicht mehr oder weniger wert als 
ein Kommentar.

von Dirk B. (dirkb2)


Lesenswert?

bla (und auch i) sollten vom Typ size_t sein.
Der ist in <stdint.h> definiert.

Beim ersten return aus deiner Funktion berechnest du den Mittelwert 
falsch.

Wenn du die Anzahl der Elemente im Array ermittel willst, dann schreib 
beim Divisor die ein Element aus dem Array hin

size_t bla  = sizeof(zahlen)/sizeof(zahlen]0]);
oder
size_t bla  = sizeof(zahlen)/sizeof(*zahlen);

Dann ist da auch noch korrekt, wenn sich der Typ von zahlen ändert.

Bei Übergabe von Arrays an Funktionen solltest du immer die Größe vom 
Array mit angeben.
Unbedingt, wenn das Array beschrieben wird.

strcpy ist z.B eine Fehlkonstruktion. strncpy ist auch nicht besser.

von Theor (Gast)


Lesenswert?

tictactoe schrieb:
> Theor schrieb:
>> Wäre hingegen die Grösse ausdrücklich angegeben
>> worden int x [17] dann würde sizeof diese Information verwenden.
>
> Ganz und gar nicht. Ein solcher Art Parameter wäre ebenfalls äquivalent
> zu int* x; die 17 an dieser Stelle ist nicht mehr oder weniger wert als
> ein Kommentar.

Du hast recht. Ich habe etwas Falsches geschrieben.

Man siehe 6.5.3.4. der Standards.
C11   http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
C18 
http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf


Da muss der Wunsch der Vater des Gedankens gewesen sein.
Und logisch kommt es mir auch vor, denn der Fall int x [17] würde ja 
einen kompletten Typen darstellen.

Aber das nur nebenbei.

von Theor (Gast)


Lesenswert?

>> Theor schrieb:
[...]
> Da muss der Wunsch der Vater des Gedankens gewesen sein.
> Und logisch kommt es mir auch vor, denn der Fall int x [17] würde ja
> einen kompletten Typen darstellen.

Obwohl ...

Das würde zu einer anderen Komplikation führen, wenn nämlich die 
Funktion in einem einzigen Programm auf Arrays verschiedener Länge 
ausgeführt werden soll. Dann würde für jede Variation der Länge eine 
eigene Funktion nötig sein. Ist also schon sinnvoll. Na gut. :-)

von Nop (Gast)


Lesenswert?

Deswegen haben C-Funktionen das typische Idiom, daß sie einerseits einen 
Pointer übergeben bekommen und (sofern die Länge nicht fix ist) zweitens 
einen Längenparameter vom Typ size_t.

von Rolf M. (rmagnus)


Lesenswert?

Theor schrieb:
> Entscheidend ist dass in main die Grösse des Arrays bekannt ist. In der
> Parameterliste aber nicht, da die Grössenangabe fehlt.

Das ist zu kurz gedacht. Es hat nicht direkt mit Größeninformationen zu 
tun, sondern damit, dass wir in main ein Array haben, in der 
Paramterliste aber einen Zeiger. Das sind zwei ganz unterschiedliche 
Dinge.

Dirk B. schrieb:
> Bei Übergabe von Arrays an Funktionen solltest du immer die Größe vom
> Array mit angeben.
> Unbedingt, wenn das Array beschrieben wird.

Ob es beschrieben wird oder nicht, spielt keine Rolle. Wenn man ein 
Array übergibt, muss die aufgerufene Funktion auf irgendeine Art wissen, 
wie lang das Array ist. Die gängigen Varianten sind ein Array fixer 
Länge, ein zusätzlicher Parameter mit der Länge und irgendeine Form von 
Ende-Kennung, wie z.B. bei C-Strings das \0 am Ende.

> strcpy ist z.B eine Fehlkonstruktion. strncpy ist auch nicht besser.

Hä?

von Wilhelm M. (wimalopaan)


Lesenswert?

Du kannst aber in einem template-nicht-typ-parameter die Dimension des 
Arrays ableiten.

Offensichtlich (<iostream>) verwendest Du C++.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Du kannst aber in einem template-nicht-typ-parameter die Dimension des
> Arrays ableiten.

Etwa sowas:
1
template <size_t S>
2
double MinMaxDurch(int (&zahlen)[S]) {
3
...

von Dirk B. (dirkb2)


Lesenswert?

Rolf M. schrieb:
> Dirk B. schrieb:
>> Bei Übergabe von Arrays an Funktionen solltest du immer die Größe vom
>> Array mit angeben.
>> Unbedingt, wenn das Array beschrieben wird.
>
> Ob es beschrieben wird oder nicht, spielt keine Rolle. Wenn man ein
> Array übergibt, muss die aufgerufene Funktion auf irgendeine Art wissen,
> wie lang das Array ist. Die gängigen Varianten sind ein Array fixer
> Länge, ein zusätzlicher Parameter mit der Länge und irgendeine Form von
> Ende-Kennung, wie z.B. bei C-Strings das \0 am Ende.

Ein Array kann auch nur zu einem Teil gefüllt sein.
Beim Lesen spielt es keine Rolle, wie groß das Array ist, wenn man eine 
Endekennung hat.
Beim Schreiben möchte man evtl. den ganzen Bereich ausnutzen. Und dann 
sollte man die Größe kennen.
1
char feld[200] = "Hallo Welt!"; // 12 von 200 belegt
2
strcpy(feld,  "hello world!");


>> strcpy ist z.B eine Fehlkonstruktion. strncpy ist auch nicht besser.
>
> Hä?
1
char feld[] = "Hallo Welt!";    // 12 von 12 belegt
2
strcpy(feld,  "hello world!");  // Upsi

von Nop (Gast)


Lesenswert?

Dirk B. schrieb:
1
char feld[] = "Hallo Welt!";    // 12 von 12 belegt
2
strcpy(feld,  "hello world!");  // Upsi

Das kommt halt davon, wenn man im Programm deutsch und englisch mischt. 
;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Den Fehler kann man zwar durch templates vermeiden wie ich oben gezeigt 
habe, allerdings ist das Grundproblem, dass überhaupt mit rohen Arrays 
gearbeitet wird in dem Stück C++-Code. Besser von vornherein 
std::array<> für statische Arrays einsetzen.

Um das Problem des TO zu verstehen, bitte mal nach "decaying of array 
designator" googlen.

von Theor (Gast)


Lesenswert?

Rolf M. schrieb:
> Theor schrieb:
>> Entscheidend ist dass in main die Grösse des Arrays bekannt ist. In der
>> Parameterliste aber nicht, da die Grössenangabe fehlt.
>
> Das ist zu kurz gedacht. Es hat nicht direkt mit Größeninformationen zu
> tun, sondern damit, dass wir in main ein Array haben, in der
> Paramterliste aber einen Zeiger. Das sind zwei ganz unterschiedliche
> Dinge.
>
> [...]


Eigentlich finde ich nicht, dass das zu kurz gedacht ist. Eher halte ich 
es für plausibel, dass ich einen oder zwei Schritte tiefer gedacht habe.
Zugegeben: Das ich zu kurz gedacht haben soll, provoziert mich auch ein 
bisschen. :-) Möglich ist das natürlich schon, aber ich halte Deinen 
Einwand nicht für ausschlaggebend für diese Beurteilung.


Aber zum Thema, falls Du darauf eingehen magst:

Ich denke, dass es, - mal vom Standpunkt eines Compilerbauers aus 
gesehen -, ausgehend vom Quelltext möglich wäre, die 
Grösseninformation eines Array-Parameters der Form "Typ Name [Groesse]" 
zu gewinnen.

Ich denke weiter, dass die Umwandlung eines Array-Parameters in einen 
Zeiger darauf nicht zwingend erfordert, die Grösseninformation zu 
ignorieren.

Es scheint mir ein Widerspruch zu bestehen:
Im Fall einer definierten auto-Variable (also das Beispiel mit einem 
definierten Array in main) wird es ja auch als Zeiger behandelt und 
die Grösseninformation erhalten. (Ich meine damit, dass lediglich 
Ausdrücke mit Zeigern oder Element-Indexierung [was ja auf Zeiger 
zurückzuführen ist] möglich sind. Das Array als Ganzes wiederum muss 
bzw. kann nur als Zeigeroperand erscheinen.
Es sind in C gar keine Operanden möglich, die ein Array als Ganzes 
behandeln - mit einer Ausnahme! Nämlich eben "sizeof" (OK. OK. Abgesehen 
von align-Dingsbums :-) ).

Wenn das so ist, dann ist die Aussage, dass es auf das Vorhandensein der 
Grössenangabe ankommt nicht falsch und nicht zu kurz gedacht.

Es scheint mir möglicherweise eine Fehldeutung des Standards darin zu 
liegen, dass sich die Umwandlung von Arrays in Zeiger mit Verlust der 
Grösseninformation, während der Kompilierungszeit, in dem einen Fall auf 
auto-Variablen nicht bezieht, in dem anderen Fall eines Parameters 
aber doch . Jedenfalls steht das nirgendwo ausdrücklich, meine ich. 
Oder ich habe was übersehen.

Was meinst Du dazu?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Was ist denn deine Deutung des Standards? Dass Pointer die 
Größeninformation doch erhalten (dürfen)? Wie kommt man denn laut 
Standard an die Größe dran, denn sizeof(Pointer) soll ja die Größe des 
Pointers selbst liefern. Nirgendwo im Standard steht dass Pointer eine 
Array-Größe speichern, deshalb geht bei der Konvertierung nunmal 
zwangsweise etwas verloren. Solange man das Array in der main() weiter 
verwendet, wird ja nichts konvertiert, und es geht nichts verloren. Die 
Größeninformation ist hier aber nur dem Compiler bekannt und wird in den 
sizeof()-Ausdruck eingesetzt; sie wird aber nicht zur Laufzeit irgendwo 
vorgehalten.

von Theor (Gast)


Lesenswert?

Niklas G. schrieb:
> Was ist denn deine Deutung des Standards? Dass Pointer die
> Größeninformation doch erhalten (dürfen)? Wie kommt man denn laut
> Standard an die Größe dran, ...

Darüber steht ja im Standard nichts. Das ist ein Implementierungsdetail 
des Compilers.

Die Frage scheint ja zu sein, ob man die Kompilation als monolithischen 
Prozess betrachtet. Ob es wahr ist, dass es einen Zeitpunkt resp. eine 
Phase gibt bevor das array als Pointer behandelt wird und einen zu dem 
das getan wird oder nicht.
Das erste scheint ja im Fall eines auto-Arrays, definiert innerhalb 
einer Funktion der Fall zu sein. Denn es ist ja in diesem Fall möglich 
sizeof durch die Grösse des Arrays zu ersetzen.
Falls ich aber das zweite für gegeben hallte, dann sollte es auch für 
auto-Arrays nicht möglich sein, sizeof zu verwenden.
> ... denn sizeof(Pointer) soll ja die Größe des
> Pointers selbst liefern.
Nicht im Falle eines auto-Arrays definiert innerhalb der Funktion.

> Nirgendwo im Standard steht dass Pointer eine
> Array-Größe speichern, deshalb geht bei der Konvertierung nunmal
> zwangsweise etwas verloren. Solange man das Array in der main() weiter
> verwendet, wird ja nichts konvertiert, und es geht nichts verloren.

Da, wie ich oben schrieb sämtliche Ausdrück (abgesehen von sizeof) auf 
Arrays als Pointer beruhen (wenn auch austauschbar mit arrays in 
Index-Ausdrücken), muss ja in einer Phase die Länge vorhanden sein, 
während sie es in einer nachfolgen Phase, bei der Umsetzung in 
Assembler, nicht mehr sein muss. Die Ersetzung von sizeof ist ja dann 
schon erledigt.

Die Grössenangabe bei auto-Arrays wird ein Teil eines Tupels im 
Syntaxbaum sein. Das aber geht auch für Parameter so. Meinst Du nicht?

Kurz gesagt: Es ergibt sich aus dem Standard und auch meiner Deutung 
davon nicht, dass es in dem einen Fall geht und in dem anderen Fall 
nicht geht oder nicht gehen darf. In beiden Fällen sind die 
Größenangaben vorhanden.

> Die
> Größeninformation ist hier aber nur dem Compiler bekannt und wird in den
> sizeof()-Ausdruck eingesetzt; sie wird aber nicht zur Laufzeit irgendwo
> vorgehalten.

Ich weiss nicht worauf Du damit hinaus willst. Das das zur Laufzeit noch 
vorhanden ist oder sein muss, habe ich gar nicht behauptet. Es ergibt 
sich auch aus meinen Einwänden nicht.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Theor schrieb:
> Nicht im Falle eines auto-Arrays definiert innerhalb der Funktion.

Das ist ja auch ein Array und kein Pointer. sizeof-Ersetzung passiert 
halt bevor der Compiler aus Arrays Pointer(-Arithmetik) macht.

Theor schrieb:
> muss ja in einer Phase die Länge vorhanden sein,
> während sie es in einer nachfolgen Phase, bei der Umsetzung in
> Assembler, nicht mehr sein muss. Die Ersetzung von sizeof ist ja dann
> schon erledigt.
Ja.

Theor schrieb:
> Die Grössenangabe bei auto-Arrays wird ein Teil eines Tupels im
> Syntaxbaum sein.
Ja.

Theor schrieb:
> Das aber geht auch für Parameter so. Meinst Du nicht?
Wie denn? Im Syntaxbaum steht "Funktion MinMaxDurch hat Parameter vom 
Typ double*". Da ist keine Größenangabe bekannt. Wo soll die herkommen? 
Die Funktion wird ja ggf. von verschiedenen Dateien aus aufgerufen, wo 
überall Pointer auf unterschiedlich große Speicherbereiche übergeben 
werden könnten.

Der Compiler betrachtet jede Funktion für sich; beim Kompilieren von 
MinMaxDurch weiß er nicht, mit welchen Array-Größen sie aufgerufen wird. 
Oder wie meinst du das?



Theor schrieb:
> In beiden Fällen sind die
> Größenangaben vorhanden.
Die Größenangabe kommt erst beim tatsächlichen Aufruf der Funktion aus 
einer bestimmten Stelle zustande. Die kann aber variabel sein, landet 
also nicht im Syntaxbaum.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Theor schrieb:
> Da, wie ich oben schrieb sämtliche Ausdrück (abgesehen von sizeof) auf
> Arrays als Pointer beruhen

Ein ausserhalb der Parameterliste deklariertes Array ist zunächst vom 
Typ her kein Pointer, sondern ein Array und behält daher eine ggf 
bekannte Grösse. Erst in Expressions wird es ggf zum Pointer.

C11 6.3.2.1.3: "Except when it is the operand of the sizeof operator, 
the _Alignof operator, or the unary & operator, or is a string literal 
used to initialize an array, an expression that has type ‘‘array of 
type’’ is converted to an expression with type ‘‘pointer to type’’ that 
points to the initial element of the array object and is not an lvalue."

> Kurz gesagt: Es ergibt sich aus dem Standard und auch meiner Deutung
> davon nicht, dass es in dem einen Fall geht und in dem anderen Fall
> nicht geht oder nicht gehen darf. In beiden Fällen sind die
> Größenangaben vorhanden.

Ein Array in einer Parameterdeklaration wird hingegen bereits per 
Deklaration zum Pointer, nicht erst bei der Verwendung. Damit geht die 
Information über die Grösse des Arrays verloren.

C11 6.7.6.3.7: "A declaration of a parameter as ‘‘array of type’’ shall 
be adjusted to ‘‘qualified pointer to type’’, ..."

Da sizeof(Pointer) die Grösse eines Pointers angibt und in der 
Definition von sizeof kein entsprechender Sonderfall aufgeführt wird, 
ist die Sache damit geklärt. Egal wie man in der Parameterdeklaration 
ein Array reinschreibt, bei sizeof gibts die Grösse des Pointers, nicht 
die des Arrays.

Ob man das als sinnvoll betrachtet, oder ob die Information eigentlich 
vorhanden wäre, interessiert den Standard nicht. Altlast.

: Bearbeitet durch User
von Theor (Gast)


Lesenswert?

Niklas G. schrieb:
> Theor schrieb:
>> Nicht im Falle eines auto-Arrays definiert innerhalb der Funktion.
>
> Das ist ja auch ein Array und kein Pointer. sizeof-Ersetzung passiert
> halt bevor der Compiler aus Arrays Pointer(-Arithmetik) macht.

Lassen wir das mal (wenigstens zeitweise) aussen vor und kommen darauf 
zurück. OK?

> [...] (Gekürzt wegen Übereinstimmung in diesem Punkt).

>
> Theor schrieb:
>> Das aber geht auch für Parameter so. Meinst Du nicht?
> Wie denn? Im Syntaxbaum steht "Funktion MinMaxDurch hat Parameter vom
> Typ double*". Da ist keine Größenangabe bekannt. Wo soll die herkommen?

Das muss aber vom Standpunkt des Compilerimplementierers nicht 
zwingend so sein. Er könnte sich genauso gut entscheiden im Syntaxbaum 
auch die Grössenangabe eines als Parameter deklarierten Arrays zu 
speichern. Was spricht dagegen? Nur die willkürliche Voraussetzung , 
dass während der Baum gebaut wird, alle array-parameter grundsätzlich 
als Zeiger betrachtet werden. Hingegen beim parsen von Code der 
innerhalb einer Funktion ein auto-Array enthält ist das nicht der Fall. 
Wieso?

> Die Funktion wird ja ggf. von verschiedenen Dateien aus aufgerufen, wo
> überall Pointer auf unterschiedlich große Speicherbereiche übergeben
> werden könnten.

Das ist mein Einwand oben gegen meine eigene Ansicht gewesen. Siehe: 
Beitrag "Re: C sizeof Funktion in main vs in Funktion"
Nur das ich das eben nicht mehr für stichhaltig halte.

Falls ich eine Funktion haben will, die Arrays als Parameter enthalten 
soll und ich diese Funktion an verschiedenen Stellen mit Arrays 
verschiedener Länge aufrufen will, steht es mir ja frei dies 
ausdrücklich zuzulassen und zu schreiben:
1
funktion (Typ Name [], ...)
oder
1
funktion (Typ * Name, ...)

(Mit der Konsequenz dass ich sizeof ganz zweifelsfrei nicht verwenden 
kann).

Schreibe ich hingegen
1
funktion (Typ Name [Laenge], ...

dann ist das semantisch ganz präzise zu interpretieren: Die Funktion 
kann ausschliesslich mit Arrays bestimmter Länge als Parameter 
aufgerufen werden. Was mir überhaupt der Sinn zu sein scheint, die 
Längenangabe syntaktisch zuzulassen. Oder gibt es einen anderen?

> [...]
> Theor schrieb:
>> In beiden Fällen sind die
>> Größenangaben vorhanden.
> Die Größenangabe kommt erst beim tatsächlichen Aufruf der Funktion aus
> einer bestimmten Stelle zustande. Die kann aber variabel sein, landet
> also nicht im Syntaxbaum.

Moment. Ist das ein Mißverständnis? Ich meine die folgenden beide Fälle.
1
funktion (.... ) [
2
   Typ Name [Laenge];       /* was ich im Thread als "definiertes auto-Array" bezeichne */
3
...

und
1
funktion (Typ Name [Laenge], ...

Im der zweiten Variante ist die Länge nicht erst beim Aufruf bekannt, 
sondern schon bei der Definition (und bei einer evtl. Deklaration).
Also ist in beiden Fällen die Grössenangabe vorhanden.

von (prx) A. K. (prx)


Lesenswert?

Theor schrieb:
> Er könnte sich genauso gut entscheiden im Syntaxbaum
> auch die Grössenangabe eines als Parameter deklarierten Arrays zu
> speichern.

Die Syntax selbst ist die falsche Stelle. Diese Angabe geht verloren, 
wenn im Rahmen der Abarbeitung einer Deklaration die Typ-Spezifikation 
des Parameternamens erzeugt wird.

> Was spricht dagegen?

Der C-Standard. Und der definiert es so, weil es immer so war. Es gibt 
nicht viele Fälle, in denen ein C Standard zu einem früheren Standard 
(echt oder de fakto) inkompatibel wird.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Theor schrieb:
> Moment. Ist das ein Mißverständnis? Ich meine die folgenden beide Fälle.

Ach! Dann ist das was anderes. Man hat sich vermutlich aus Gründen der 
Kompatibilität dazu entschieden, dass Array-Parameter mit Größenabgabe 
auch nur als Pointer behandelt werden, denn es wird ja letztlich auch 
nur ein Pointer übergeben. Ich weiß jetzt nicht wo das im Standard 
steht, aber wenn es falsch interpretiert wird würde das heißen dass 
etablierte Compiler wie GCC hier falsch liegen - unwahrscheinlich

von Theor (Gast)


Lesenswert?

Niklas G. schrieb:
> Theor schrieb:
>> Moment. Ist das ein Mißverständnis? Ich meine die folgenden beide Fälle.
>
> Ach! Dann ist das was anderes. Man hat sich vermutlich aus Gründen der
> Kompatibilität dazu entschieden, dass Array-Parameter mit Größenabgabe
> auch nur als Pointer behandelt werden, denn es wird ja letztlich auch
> nur ein Pointer übergeben. Ich weiß jetzt nicht wo das im Standard
> steht, aber wenn es falsch interpretiert wird würde das heißen dass
> etablierte Compiler wie GCC hier falsch liegen - unwahrscheinlich

Was ich meine und woraus ich das ableite, ist vielleicht etwas 
kompliziert oder ich drücke mich nicht prägnant genug aus.

Was ich sagen will, ist dass eine zweite Deutung gibt, die auch nicht im 
Widerspruch zum Standard steht.

Die Fussnote

"(105) When applied to a parameter declared to have array or function 
type, the sizeof operator yields the size of the adjusted
(pointer) type (see 6.9.1)." [aus dem C17_proposal, aber die Fussnote 
taucht auch in früheren Standards auf]

kann so interpretiert werden, dass sie sowohl 1. für die Phase des 
Aufbaus des Syntaxbaumes gilt und für den Ersatz von sizeof durch die 
angegebene Länge, als auch 2. für die Codesynthese.

Ich meine aber, es würde keinerlei Widersprüche mit der restlichen 
Semantik und dem Standard aufwerfen, wenn sizeof auf array-Parameter mit 
expliziter Längenangabe anwendbar wäre, so das es genau diese 
Längenangabe schon während der Phase des Syntaxbaumaufbaus und Ersatz 
ergibt.

Was bis dahin nicht ersetzt werden konnte, bleibt ohnehin nur als Zeiger 
zu deuten und sizeof ergäbe folgerichtig die Grösse des Zeigertypen.

Dafür, dass es diesen Unterschied in den Compilerimplementierungn gibt 
spricht, dass im Falle von auto-Arrays ja gerade das Array nicht als 
Pointer interpretiert wird, und der Ersatz geschieht. Während der ersten 
Phase des Aufbaus des Syntaxbaums wird die Grössenangabe in sizeof auf 
das Array und nicht auf den Zeigertyp bezogen.

Der Unterschied beruht ja vom Standard aus nur auf dem "Parameter sein" 
und darauf, dass die Compilation von den Implementierern in dem einen 
Fall als homogener Prozess angesehen wird (bei der Parameterbehandlung; 
aha, ein Pointer) anderseits aber als heterogener (bei den auto-Arrays; 
aha, erstmal ein Array mit Grösse für sizeof, dann aber ein Pointer).

Ich hoffe das ist jetzt etwas prägnanter ausgedrückt.

von Theor (Gast)


Lesenswert?

Oder noch anders: Wenn sizeof technisch gesehen auf Parameter arrays mit 
Längenangabe anwendbar ist, dann schränkt die Fussnote die Anwendung von 
sizeof unnötig ein.

Es wäre hinreichend, wenn die Einschränkung nur für "incomplete types" 
von Arrays in Parametern gelten würde.

Diese Einschränkung gilt ja ohnehin auch für definierte Zeiger bzw. 
innerhalb von Funktionen.
1
funktion () [
2
  int a[];
3
  int * b;
4
...

ist es ja auch und ganz folgerichtig so, dass sizeof die Grösse des 
Zeigertyps ergibt.

von (prx) A. K. (prx)


Lesenswert?

Theor schrieb:
> Ich hoffe das ist jetzt etwas prägnanter ausgedrückt.

Prägnant, aber falsch.

Theor schrieb:
> Oder noch anders: Wenn sizeof technisch gesehen auf Parameter arrays mit
> Längenangabe anwendbar ist, dann schränkt die Fussnote die Anwendung von
> sizeof unnötig ein.

Man hätte C anfangs anders definieren können, oder später inkompatibel 
zu früher. Hat man aber nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Theor schrieb:

> Falls ich eine Funktion haben will, die Arrays als Parameter enthalten
> soll und ich diese Funktion an verschiedenen Stellen mit Arrays
> verschiedener Länge aufrufen will, steht es mir ja frei dies
> ausdrücklich zuzulassen und zu schreiben:
>
>
1
> funktion (Typ Name [], ...)
2
>

Ja, dann mach das doch!
1
void function(const std::array<float, 42>&);

von Ma S. (turbotorsten)


Lesenswert?

C, Zeiger, Arrays, Sizeof....eine Thematik die wohl in semtlichen 
Sparten die Leute beschäfftigt...
https://lkml.org/lkml/2015/9/3/428
..Linus of it´s finest,freundlich wie man ihn eben kennt regt er sich 
auch über das sizeof Problem auf.

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.