C Fehler: vla-parameter
-
Ich hab folgende Funktion in C:
void mulMatrix(size_t yA, size_t xA, f32_t a[yA][xA], size_t yB, size_t xB, f32_t b[yB][xB], f32_t result[yB][xB]);
Der Compiler spuckt mir nun aber folgendes aus:
/mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:18:45: warning: argument 7 of type ‘float[yB][xA]’ declared with mismatched bound argument 2 [-Wvla-parameter] 17 | void mulMatrix(size_t yA, size_t xA, f32_t matrixA[yA][xA], size_t yB, size_t xB, | ~~~~~~~~~ 18 | f32_t matrixB[yB][xB], f32_t matrixC[yB][xA]) {
Warum kommt dieses Warning an der Stelle nun? Liegt es daran, dass per Konvention die "limiter" direkt vor dem Array kommen müssen?
-
const
?
-
@Fragender
Bringt leider auch nichts, kommt folgender Fehler:/mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:18:45: warning: argument 7 of type ‘float[yB][xA]’ declared with mismatched bound argument 2 [-Wvla-parameter] 17 | void mulMatrix(const size_t yA, const size_t xA, f32_t matrixA[yA][xA], const size_t yB, const size_t xB, | ~~~~~~~~~~~~~~~ 18 | f32_t matrixB[yB][xB], f32_t matrixC[yB][xA]) {
Verstehe aber nicht genau warum, hab natürlich in CMake -Wall -Wextra -Wpedantic angemacht, aber interessiert mich schon, warum der das nicht mag. Googlen brachte mich auch nciht wirklich weiter
-
Ist das die komplette Fehlermeldung? Eigentlich sollte da noch weitere Information zur Erläuterung folgen.
Und ist das 100% 1:1 der Code, der den Fehler verursacht? Wenn du jetzt Ja sagst, lügst du, denn in der Fehlermeldung stehen andere Bezeichner als in dem Code, den du uns zeigst…
Letzteres könnte aber auch schon das Problem sein, denn die vla-parameter-Warnung ist dafür bekannt, etwas übereifrig zu sein, und zum Beispiel schon bei inhaltlich identischen Redeklarationen zu warnen, bloß weil sich ein paar Bezeichner ändern. Aber sie kann halt auch recht haben, wenn du da tatsächlich dich irgendwie vertippt haben solltest. Kann ja leicht passiert sein, da du da ja offensichtlich mit den Namen der Argumente herumgespielt hast.
Daher: Problem bitte auf einen minimalen Code reduzieren, der noch exakt die Fehlermeldung produziert. Die Chancen stehen gut, dass du die Ursache dabei bereits selber findest, etwa wenn die Fehlermeldung plötzlich verschwindet, nachdem du eine eventuelle vorhergehende Deklaration raus gelöscht hast. Dann kannst du genauer gucken, ob die Warnung berechtigt oder übereifrig war, oder im Zweifel hier noch einmal fragen.
@Fragender: Bitte nicht dumm rum raten. Da wird nicht einmal ein Array definiert, wie du zu glauben scheinst.
-
@SeppJ sagte in C Fehler: vla-parameter:
Da wird nicht einmal ein Array definiert, wie du zu glauben scheinst.
Das hab ich auch nicht geglaubt... Semantisch ist das einfach nur eine Arrayübergabe an eine Funktion, wobei das Array genau n "Plätze" hat. (denke ich)
-
@TheCrazyDev64: Du verwendest als letzten Parameter
matrixC[yB][xA]
, erwartet wird aberresult[yB][xB]
(alsoxB
anstattxA
).
Die Fehlermeldung erscheint, weil die Indizes von VLA-Arrays an andere Funktionsparameter fest gebunden sind.Hast du denn selber die Funktion definiert, denn logisch sollte ja trotzdem die Matrixmultiplikation aus der Zeilenzahl der 1. Matrix und der Spaltenzahl der 2. Matrix bestehen?
-
@Th69 Tatsache, da hat sich ein Typo eingeschlichen zwischen Deklaration und definition. Gibts ggf. einen Trick in CLion bisschen besser zwischen Header und Source Datei zu wechseln?
@SeppJ Wenn ich das jetzt mit dem Fehler Kompiliere kommt komplett folgende Ausgabe:
====================[ Build | tests | Debug ]=================================== C:\WINDOWS\system32\wsl.exe --distribution kali-linux --exec /usr/bin/fish -c "export CLION_IDE=TRUE && export CLICOLOR_FORCE=1 && export TERM=xterm && export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' && export JETBRAINS_IDE=TRUE && cd /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/cmake-build-debug && /usr/bin/cmake --build /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/cmake-build-debug --target tests -- -j 6" your 131072x1 screen size is bogus. expect trouble your 131072x1 screen size is bogus. expect trouble [ 9%] Building C object CMakeFiles/tests.dir/test/tests/matrixTest.c.o [ 18%] Building C object CMakeFiles/tests.dir/src/helper/matrix.c.o /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:18:45: warning: argument 7 of type ‘float[yB][xA]’ declared with mismatched bound argument 2 [-Wvla-parameter] 17 | void mulMatrix(const size_t yA, const size_t xA, f32_t matrixA[yA][xA], const size_t yB, const size_t xB, | ~~~~~~~~~~~~~~~ 18 | f32_t matrixB[yB][xB], f32_t matrixC[yB][xA]) { In file included from /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:1: /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.h:43:22: note: previously declared as ‘float[yB][xB]’ with bound argument 5 42 | void mulMatrix(size_t yA, size_t xA, f32_t a[yA][xA], size_t yB, size_t xB, f32_t b[yB][xB], | ~~~~~~~~~ 43 | f32_t result[yB][xB]); /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c: In function ‘mulMatrix4Tuple’: /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:134:57: warning: parameter ‘res’ set but not used [-Wunused-but-set-parameter] 134 | void mulMatrix4Tuple(Matrix4 matrix, Tuple tuple, Tuple res) { | ~~~~~~^~~ [ 27%] Linking C executable tests [100%] Built target tests Build finished
Hätte ggf. Deklaration und Definition gemeinsam reinpacken sollen, dann wäre das sichtbarer gewesen. Aber ja das ist der Code, der Fehler verursacht, nur nicht der ganze scheinbar
-
Andere und vielleicht blöde Frage, aber wofür braucht man die Größenangabe bei der Parameterdeklaration, wenn diese eh nicht "fest" ist? Du willst ja Matrizen beliebiger Dimension multiplizieren, weshalb dann die Akrobatik mit
f32_t a[yA][xA]
, anstatt einfach nurf32_t a[][]
? Gewinnt man dadurch einen compile/runtime check? Verstehe ich nicht.
-
@Fragender sagte in C Fehler: vla-parameter:
Andere und vielleicht blöde Frage, aber wofür braucht man die Größenangabe bei der Parameterdeklaration, wenn diese eh nicht "fest" ist? Du willst ja Matrizen beliebiger Dimension multiplizieren, weshalb dann die Akrobatik mit f32_t a[yA][xA], anstatt einfach nur f32_t a[][]? Gewinnt man dadurch einen compile/runtime check?
Ohne Kenntnis der Größe (von allen Dimensionen bis auf die erste) kannst du die Position im Speicher nicht bestimmen.
-
@TheCrazyDev64 sagte in C Fehler: vla-parameter:
/mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:18:45: warning: argument 7 of type ‘float[yB][xA]’ declared with mismatched bound argument 2 [-Wvla-parameter] > 17 | void mulMatrix(const size_t yA, const size_t xA, f32_t matrixA[yA][xA], const size_t yB, const size_t xB, > | ~~~~~~~~~~~~~~~ > 18 | f32_t matrixB[yB][xB], f32_t matrixC[yB][xA]) { > In file included from /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.c:1: > /mnt/c/Users/theun/CLionProjects/the-raytracer-challenge/src/helper/matrix.h:43:22: note: previously declared as ‘float[yB][xB]’ with bound argument 5 > 42 | void mulMatrix(size_t yA, size_t xA, f32_t a[yA][xA], size_t yB, size_t xB, f32_t b[yB][xB], > | ~~~~~~~~~ > 43 | f32_t result[yB][xB]);
Genau. Das hier gehört alles zusammen und sagt dir, dass du es einmal mit Parameter #2 (xA) und einmal mit Parameter #5 (xB) deklariert hast.
-
@wob sagte in C Fehler: vla-parameter:
@Fragender sagte in C Fehler: vla-parameter:
Andere und vielleicht blöde Frage, aber wofür braucht man die Größenangabe bei der Parameterdeklaration, wenn diese eh nicht "fest" ist? Du willst ja Matrizen beliebiger Dimension multiplizieren, weshalb dann die Akrobatik mit f32_t a[yA][xA], anstatt einfach nur f32_t a[][]? Gewinnt man dadurch einen compile/runtime check?
Ohne Kenntnis der Größe (von allen Dimensionen bis auf die erste) kannst du die Position im Speicher nicht bestimmen.
Das war nicht das, was ich geschrieben hatte. Die Größe ist doch durch
size_t
bekannt.
-
@Fragender bin jetzt kein Experte, aber size_t ist einfach ein Typ je nach system, der Aussage wie groß ein Array maximal sein kann. Also z.b. kann man nur den 16bit Bereich ausfüllen. Size_t sagt also nicht aus, dass das automatisch dem Array zugeordnet wird
Mit meiner Schreibweise gibt man dem Compiler die Information, dass er damit klarkommt auf die richten Indexe zuzugreifen. Bei 1D Arrays ist das theoretisch vernachlässigbar, aber bei 2d nicht, da [1][0] im speicher nach [0][n] liegt
Zumindest ist das mein gefährliches Halbwissen
-
Meiner Auffassung nach, ist und bleibt es Aufgabe des Programmierers, die richtigen Größen zu übergeben. Das doppelt anzugeben, ändert daran ja nix... der Programmierer kann ja immernoch Nonsense übergeben, und der Compiler würde nicht meckern... Die "common practice"/das Pattern scheint mir deshalb nicht richtig zu sein.
-
@Fragender Da wird nichts doppelt angegeben.
Es werden die Dimensionen und der Anfang vom Array übergeben.
Hier wird aber der Pointer auf das Array hinter einem VLA versteckt, so dass man in der Funktion auch die Arrayschreibweise nehmen kann.
Was ab 2D-Arrays durchaus etwas übersichtlicher ist.
-
Macht es da nicht Sinn, eine Struktur zu definieren? Sowas wie
typedef struct tagArray2D { f32_t Elements[...][...]; // hier passende Deklaration, oder auch nur einen Zeiger für eine Art "ArrayView2D" unsigned int Rows; unsigned int Columns; } Array2D;
-
@DocShoe meines Wissens nach geht das nicht, da ein struct eine feste Größe hat. Ich könnte ein Pointer speichern, aber wenig Interesse das alles via malloc zu lösen
Vielleicht muss ich es aber sowieso via malloc lösen, weiß derzeit nicht wie es sich auf den Stack verhält
-
@Fragender die mulMatrix Funktion kann mit verschiedenen Matrizen umgehen. Daher brauche ich die Dimensionen. Und damit ich mir das Leben einfacher mache, sag ich dem Compiler dass der diese Zahlen nehmen kann zum berechnen der Speicherposition. Denn arr[1][0] liegt bei 1*dim2Size+0
Da dim2Size für eine 4x4 anders ist als für eine 2x2 kann der Compiler ohne die Angabe das nicht berechnenIch kann natürlich auch nur den Pointer annehmen und dann mit der obigen Rechnung selbst drauf zugreifen, aber das ist unlesbarer und hab auch Mal gesehen dass das via Array sogar minimal schneller sei
-
Du kannst das ja auch so lösen:
typedef struct tagArray2D { f32_t* Elements; unsigned int Rows; unsigned int Columns; } Array2D; void f( Array2D* arr ) { ... } void g() { f32_t data_1[10]5]; f32_t data_2[50]; Array2D arr; arr.Elements = data_1; // oder data_2 arr.Columns = 10; arr.Rows = 5; f( &arr ); }
Das
Array2D
ist dabei ein View, es besitzt die Daten nicht, sondern stellt dir nur eine Möglichkeit zur Verfügung, wie du auf die Daten "gucken" kannst.
-
@Fragender sagte in C Fehler: vla-parameter:
Andere und vielleicht blöde Frage, aber wofür braucht man die Größenangabe bei der Parameterdeklaration, wenn diese eh nicht "fest" ist? Du willst ja Matrizen beliebiger Dimension multiplizieren, weshalb dann die Akrobatik mit
f32_t a[yA][xA]
, anstatt einfach nurf32_t a[][]
? Gewinnt man dadurch einen compile/runtime check? Verstehe ich nicht.Das liegt daran wie C Arrays an Subroutinen übergibt, nämlich nach dem Übersetzen als reiner Zeiger ohne jede Information. Wenn das Array zum Übersetzungszeitpunkt bekannt ist, werden überall schon beim Übersetzen die passenden Werte eingesetzt. Ist das nicht der Fall weiß der Compiler nur, dass ein Array auf T übergeben wird. Wie groß es ist und wie viele Dimensionen das hat, ist ihm nicht bekannt.
VLAs in C haben so ihre Probleme, aber man kann zumindest sie problemlos an Subroutinen in der passenden Größe übergeben. Wer es komfortabler will, muss eine andere Sprache nutzen.
-
@TheCrazyDev64 sagte in C Fehler: vla-parameter:
@DocShoe meines Wissens nach geht das nicht, da ein struct eine feste Größe hat. Ich könnte ein Pointer speichern, aber wenig Interesse das alles via malloc zu lösen
Das ist der übliche Weg, unter anderem weil das mit all den historischen Codes und allen anderen Sprachen funktioniert. Wenn man mathematische Berechnungen durchführen will, dann wäre meine Empfehlung entweder C++ oder Fortran zu nehmen.
P.S. VLAs funktionieren in C++ nicht bzw. nur als proprietäre Erweiterung bei bestimmten Compilern.