Auch hier schon sehr oft diskutiert, dass
1 | |
einfach falsch (weil: falsch-interpretierbar) ist. Durch Zufall habe ich dazu https://lkml.org/lkml/2015/9/3/428 gefunden.
|
Anzeige
|
Gegen array[Size]Auch hier schon sehr oft diskutiert, dass
einfach falsch (weil: falsch-interpretierbar) ist. Durch Zufall habe ich dazu https://lkml.org/lkml/2015/9/3/428 gefunden. Wilhelm M. schrieb: > https://lkml.org/lkml/2015/9/3/428 "Please people. When I see these kinds of obviously bogus code problems, that just makes me very upset." Wilhelm M. schrieb: > void foo(int array[Size]); Warum sollte man so etwas machen? Visual Studio erkennt zumindest was wirklich gemeint ist (Siehe Bild). Adam P. schrieb: > Warum sollte man so etwas machen? Das frage ich mich auch. Wer so etwas macht, hat einfach C nicht verstanden. Tatsache ist aber, dass es (hier) oft gemacht wird bzw. der Folgefehler (sizeof()) gemacht wird.
Gast
#6180887
Wilhelm M. schrieb: > https://lkml.org/lkml/2015/9/3/428 Kann man jemandem Glauben schenken der so eine Gossensprache benutzt? Programmierer schrieb: > Kann man jemandem Glauben schenken der so eine Gossensprache benutzt? Ich stimme ja mit vielen seiner Äußerungen nicht(!) überein, und seine verbale Ausdrucksweise ist nun allgemein bekannt, aber hier hat er wirklich recht.
Gast
#6180894
Programmierer schrieb: > Wilhelm M. schrieb: >> https://lkml.org/lkml/2015/9/3/428 > > Kann man jemandem Glauben schenken der so eine Gossensprache benutzt? Kann man jemand Glauben schenken, der keine Argumente bringt? Programmierer schrieb: > Kann man jemandem Glauben schenken der so eine Gossensprache benutzt? Nunja, aber es ist nun mal Tatsache, dass man so etwas nicht macht. Ja das mit dem sizeof() ist natürlich der Oberhammer. Dann doch lieber KISS und die Welt bleibt in ordnung ;)
Adam P. schrieb: > Dann doch lieber KISS und die Welt bleibt in ordnung ;) Oder man nimmt C++ und templates, denn der Array-Typ ist bei C++ vorhanden, an der Stelle zerfällt der Array-Bezeichner natürlich zu einem Zeigertyp. Bei templates wird die Arraygröße jedoch richtig abgeleitet. Wilhelm M. schrieb: > Oder man nimmt C++ Ja im ersten Moment sah mir das auch eher nach C++ aus, obwohl selbst dafür der Aufruf unvollständig war. Viel schlimmer wäre es, wenn so etwas gelehrt werden würde :-/ Aber ich hab schon vieles erlebt... Wilhelm M. schrieb: > Oder man nimmt C++ und templates, denn der Array-Typ ist bei C++ > vorhanden, an der Stelle zerfällt der Array-Bezeichner natürlich zu > einem Zeigertyp. Bei templates wird die Arraygröße jedoch richtig > abgeleitet. Und templates sind ja nicht einmal nötig. Im obigen Beispiel was die Größe des Arrays ja eine bekannte Konstante:
Sollte auch in C funktionieren und funktioniert natürlich auch mit Referenzen. In C wäre evtl. das verpacken eines Arrays in eine struct noch eine Lösung, bei der ich die Länge des Array in den Typen verpacken kann und damit nur zur Compile-Zeit habe? (bin kein C-Experte)
Torsten R. schrieb: > In C wäre evtl. das verpacken eines Arrays in eine struct > noch eine Lösung Ja das funktioniert, aber ist das nicht von hinten durch die Brust ins Auge ;) ? Adam P. schrieb: > aber ist das nicht von hinten durch die Brust ins Auge Ja: C ist grundsätzlich so. Da man das Typ-System nicht erweitern kann.
Gast
#6180932
> Dann doch lieber KISS und die Welt bleibt in ordnung ;) [..] > uint8_t array_2[123]; [..] > foo(array_2, sizeof(array_2)); Ersters (KISS) unbedingt. Für array_2 aber nicht sizeof() benutzen (das funktioniert hier nur zufällig wie erwartet), generischer ist sowas
Bei der Nutzung von array_1 ist es zweckmäßig, das der Codewartbarkeit ebenfalls so machen und auf das Größendefine verzichten. g457 schrieb: > (das > funktioniert hier nur zufällig wie erwartet) g457 schrieb: > #define sizeofarray(x) (sizeof(x)/sizeof((x)[0])) Ja hast recht. Es kommt halt auf den Typ drauf an und was du damit machen möchtest. Aber ja, verwende ich ebenfalls an vielen Stellen. Denn wenn du ein uint32_t Array hast und deine Variante verwendest, dann erhälst du die Anzahl der "Elemente"...Unpraktisch wenn du in der Funktion aber mit einem uint8_t Pointer die Daten verarbeiten willst...warum auch immer :-D Edit: z.B. eine Funktion die Big-Little-Endian konvertiert. Auch wenn das mit einer uint32_t + Maske gehen würde. Adam P. schrieb: > Torsten R. schrieb: >> In C wäre evtl. das verpacken eines Arrays in eine struct >> noch eine Lösung > > Ja das funktioniert, > aber ist das nicht von hinten durch die Brust ins Auge ;) ? Kommt darauf an: Wenn Du Domain-Typen hast, die an vielen Stellen verwendet werden und Arrays fester Länge sind, dann kannst Du so den Compiler dazu nutzen Fehler zur Compiler-Zeit zu finden. Was wären die Nachteile? Ich würde davon ausgehen, dass der Code nicht wesentlich ineffektiver wäre und bei konsequenter Verwendung im gesamten Projekt sollte es auch nicht vorkommen, dass overhead durch Umkopieren entstehen muss.
Gast
#6180962
Dass man in dem fall sizeof nicht nutzen kann, ist natürlich unschön. Trotzdem würde ich die Grösse immer hinschreiben, wenn möglich, schon zu Dokumentationszwecken. Code analyse tools könnte es eventuell auch helfen, Fehler aufzudecken. Wenn andere dass dann falsch verwenden, ist das nicht mein Problem. Und mit aktuellem GCC, vernünftigem Warnlevel und -Werror geht das sizeof dort ja dann auch nicht mehr. Bei Mehrdimensionalen Arrays wird es dann sogar richtig nützlich. Folgendes gibt 19 aus:
Gast
#6181094
DPA schrieb: > Bei Mehrdimensionalen Arrays wird es dann sogar richtig nützlich. > Folgendes gibt 19 aus:void test(int n, int x[][n]){ > printf("%d", x[3][1]); > } Und wie gibt man die ganze Matrix aus? n kann ich ja so ermitteln:
aber wie ermittele ich die Anzahl der Zeilen (wenn man sie nicht als Parameter mitübergibt)?
Gast
#6181109
Wilhelm M. schrieb: > Auch hier schon sehr oft diskutiert, dass > void foo(int array[Size]); > > einfach falsch Es gibt in C++ aber die richtige Lösung If you are using C++ there is a better approach, you can pass the array as a reference to the function, this way you will keep the size information: 1 // The array is passed as a reference to the function, keeping the size information (only for C++) 2 template<typename T, size_t N> 3 void func(T (&a)[N]) { 4 // Here N stores the correct size information for the array 5 // Basically N is equal to sizeof(my_array)/sizeof(my_array[0]) so the next code will work as expected: 6 for(int i = 0; i < N; ++i) { 7 a[i] = a[i] + i; 8 } 9 } 10 11 12 int main() { 13 // C-style array 14 int my_array[5] = {1, 2, 3, 4, 5}; 15 16 // Pass the array to a function 17 func(my_array); 18 return 0; 19 } Similarly, you can pass a multi-dimensional C-style array to a function without losing the size information: 1 template<typename T, size_t M, size_t N> 2 void func(T (&my_array)[M][N]) { 3 // Here M = no. of lines and N = no. of columns 4 // .... 5 } If you are interested to learn more about modern C++ I would recommend reading A Tour of C++ by Bjarne Stroustrup.
Gast
#6181120
zitter_ned_aso schrieb: > aber wie ermittele ich die Anzahl der Zeilen (wenn man sie nicht als > Parameter mitübergibt)? Na gar nicht. MaWin schrieb: > Es gibt in C++ aber die richtige Lösung Hatte ich doch oben schon geschrieben: Beitrag "Re: Gegen array[Size]" Wilhelm M. schrieb: > Auch hier schon sehr oft diskutiert, dass > > void foo(int array[Size]); > > einfach falsch (weil: falsch-interpretierbar) ist. Meiner Meinung nach ist etwas nicht falsch, nur weil es möglicherweise von einem blutigen Anfänger falsch interpretiert werden kann, denn wenn man darauf Rücksicht nehmen wollte, dürfte man 80% der Sprachelemente von C und C++ nicht verwenden. Folgende drei Deklarationen sind ja bekanntlich äquivalent:
Bei mehreren Schreibweisen für den gleichen Sachverhalt kann man die Redundanz nutzen, um dem Leser durch die gezielte Wahl einer bestimmten Alternative zusätzliche Informationen zu liefern, also eine bestimmte Absicht zu dokumentieren. I.Allg. verwende ich die drei Alternativen deswegen wie folgt: (1) für Zeiger auf einzelne Objekte. Der Sinn dahinter ist, ein Out- oder ein In/Out-Argument zu deklarieren, das in der Funktion beschrieben bzw. überschrieben wird. Innerhalb der Funktion wird auf das Objekt ausschließlich mit *arg und nicht etwa mit dem äquivalenten arg[0] zugegriffen. (2) für Zeiger auf eine Sequenz mit einer unbestimmten Anzahl von Einzelobjekten, also insbesondere auch für Arrays, wohl wissend, dass sich die Operatoren & und sizeof, auf den dem Zeiger angewandt, anders verhalten als bei einem Array. Innerhalb der Funktion wird auf die einzelnen Objekte mit arg[i] und nicht etwa mit dem äquivalenten *(arg+i) zugegriffen. (3) für Zeiger auf eine zusammenhängende Sequenz mit einer festen Anzahl SIZE von Einzelobjekten, also insbesondere auch Arrays mit genau SIZE Elementen, wohl wissend, dass der Compiler dies nicht überprüft. Innerhalb der Funktion wird auf die einzelnen Objekte wie bei (2) mit arg[i] zugegriffen. Der Anwender der Funktion erkennt damit allein aus der Deklaration (ohne die gesamte Softwaredokumentation lesen zu müssen) sofort, dass bei (2) die Funktion nicht einen Zeiger auf eine Einzelvariable, sondern ein Array o.ä. erwartet. Bei (3) erkennt er zusätzlich, dass nicht irgendein Array, sondern eins mit exakt SIZE Elementen erwartet wird. Ich schrieb oben "i.Allg.", denn ich muss zugeben, dass ich aus Faulheit oft für alle drei Anwendungsfälle auf die Schreibweise (1) zurückfalle, was immerhin den Vorteil hat, den Linus nicht zu upsetten, falls mein Code einmal in seine Hände fallen sollte ;-)
Gast
#6181689
Tja.. Wer im C Standard nicht stehen geblieben ist schreibt neuerdings auch gerne mal: void foo (int arg[static SIZE]); Der Compiler kann dann prüfen, ob das Argument, welches übergeben wird mindestens die Größe SIZE hat. Falls der Compiler in der Lage ist raus zu finden, das man diese Regel bricht gibt zumindest clang eine Warnung raus. GCC wird sicher bald nachziehen (oder hat es schon getan, bin da nicht auf dem neuesten Stand). Zudem impliziert man, das für das Argument "arg" NULL ein ungültiger Wert ist. Sehr hilfreich in der Praxis.
Gast
#6181712
Wilhelm M. schrieb: > https://lkml.org/lkml/2015/9/3/428 Was schreibt Linus da eigentlich über die "warnings"? Muss man da was aktivieren um diese zu bekommen? Ich bekomme in so einem Fall nämlich keine.
Gast
#6181726
ähm doch, ich bekomme die Warnung. aber nur hier:
mache ich aus dem Parameter einen Zeiger dann gibt es auch keine Warnung:
Aber das ist doch das gleiche (als Parameter).
Gast
#6181749
Nils schrieb: > Zudem impliziert man, das für das Argument "arg" NULL ein ungültiger > Wert ist. > > Sehr hilfreich in der Praxis. Ja, das ist interessant! Man wird da tatsächlich gewarnt. Eine gute Sache ;-) Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|