Array-Grösse zur Laufzeit festlegen?

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Array-Grösse zur Laufzeit festlegen?

Beitrag von starcow »

Abend zusammen :-)

Ich stelle grad ganz erstaunt fest, dass sich die Grösse eines Arrays anscheinend auch erst zur Laufzeit festlegen lässt.

Bislang dachte ich, dass die Grösse eines Arrays immer durch eine Konstante festgelegt werden müsse. Entweder durch eine Ganzzahlenkonstante, ein enum, ein DEFINE - oder dann implizit, durch die gleichzeitige Definition mit Werten.

Doch das scheint ja tatsächlich nur der Fall zu sein, wenn das Array global oder static deklariert wurde - sprich im Data Segment liegt und nicht auf dem Stack. So kann die Grösse eines lokales Array anscheinend auch mittels einer Variable festgelegt werden.

Code: Alles auswählen

int x = 5;
int array[x];   // Nicht möglich

int main(void)
{
	return 0;
}

Code: Alles auswählen

int main(void)
{
	int x = 5;
	int array[x];   // möglich

	return 0;
}
Ist das soweit richtig?

Ich wollte nun das ganze noch etwas weiter treiben, in der festen Erwartung, dass das folgendes Experiment nun definitiv fehlschlagen müsse:

Code: Alles auswählen

#include <stdio.h>

int main(void)
{
	unsigned int x;
	scanf("%u", &x);
	
	int array[x];
	printf("%zu", sizeof(array));
	
	return 0;	
}
Doch auch hier: Das ganze scheint zuverlässig zu funktionieren (!?). Nur kann ich mir nicht erklären, wie das Programm wissen kann, wie viel Speicher es auf dem Stack reservieren muss. Ist es denn nicht so, dass bei Eintritt in eine Funktion (also hier die main), das Programm sogleich sämtliche Variablen auf dem Stack anlegt? In dem einen Fall weiter oben stand ja bereits bei Funktionseintritt fest, wie gross das Array sein würde. Doch hier, in diesem Fall ja definitiv nicht.
Ist das, was ich hier mache vielleicht UB, und funktioniert aus irgend einem "zufälligen" (verbotenen) Grund? Oder darf das tatsächlich so gemacht werden?

LG, starcow
Zuletzt geändert von starcow am 29.11.2022, 09:56, insgesamt 1-mal geändert.
Freelancer 3D- und 2D-Grafik
mischaschaub.com
udok
Beiträge: 40
Registriert: 01.02.2022, 17:34

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von udok »

Geht glaube ich seit C99. Intern wird die _alloca Funktion aufgerufen, die den benötigten Speicher auf dem Stack anlegt.
Matthias Gubisch
Establishment
Beiträge: 470
Registriert: 01.03.2009, 19:09

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Matthias Gubisch »

Ich kenne mich in c nicht so gut aus, aber bei c++ ist es so dass der gcc das anscheinend erlaubt, msvc und clang aber nicht.

Kann also auch compilerabhängig sein
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Benutzeravatar
Lynxeye
Establishment
Beiträge: 145
Registriert: 27.02.2009, 16:50
Echter Name: Lucas
Wohnort: Hildesheim
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Lynxeye »

C99 hat dieses Feature unter dem Namen Variable Length Array eingeführt. Inzwischen halten das viele Leute für keine so gute Idee mehr, da meist vergessen wird sinnvolle Grenzen für die Größe des Arrays zu setzen und zu checken. Damit kann dieses Feature zu allerlei Sicherheitsproblemen führen. Bei GCC gibt es deshalb die Option mittels -Wvla eine Warnung zu werfen, falls VLAs verwendet werden.
udok
Beiträge: 40
Registriert: 01.02.2022, 17:34

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von udok »

Lynxeye hat geschrieben: 29.11.2022, 09:39 C99 hat dieses Feature unter dem Namen Variable Length Array eingeführt. Inzwischen halten das viele Leute für keine so gute Idee mehr, da meist vergessen wird sinnvolle Grenzen für die Größe des Arrays zu setzen und zu checken. Damit kann dieses Feature zu allerlei Sicherheitsproblemen führen. Bei GCC gibt es deshalb die Option mittels -Wvla eine Warnung zu werfen, falls VLAs verwendet werden.
Das ist meiner Meinung ein sehr sinnvolles und effizientes Feature.
Mit dem Argument darf man ja auch kein normales Array auf dem Stack anlegen - braucht ja auch Speicher.

Im Hintergrund wird bei Windows übrigens die Funktion __chkstk (=_alloca) aufgerufen, die den Speicher am Stack reserviert
(Dieselbe Funktion wird übrigens auch beim Anlegen von ganz normalen Arrays am Stack aufgerufen).
Wenn nicht genug Speicher da ist, dann gibt es eine Exception - die den Stack automatisch vergrößert.
Geht das nicht, weil man an die voreingestellte Grenze kommt gibt es eine weitere Exception,
die kann man auch abfangen, und damit eine Fehlerbehandlung machen.

Das Problem, das der Stack nicht unendlich gross ist, hast du auch bei ganz normalen Funktionsaufrufen, und auch mit malloc
(Linux ist da berüchtigt, Stichwort memory over-commitment). Man muss halt schon abfragen, ob genug Speicher vorhanden ist...

Aber es stimmt, dass der Standard Stack unter Windows als Sicherheitsfeature auf 1 MB (oder so) limitiert ist,
das lässt sich aber mit einer Compileroption raufsetzen.
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 574
Registriert: 05.07.2003, 11:17

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Lord Delvin »

starcow hat geschrieben: 28.11.2022, 22:00 Doch auch hier: Das ganze scheint zuverlässig zu funktionieren (!?). Nur kann ich mir nicht erklären, wie das Programm wissen kann, wie viel Speicher es auf dem Stack reservieren muss. Ist es denn nicht so, dass bei Eintritt in eine Funktion (also hier die main), das Programm sogleich sämtliche Variablen auf dem Stack anlegt?
Nein das ist nicht so. Das Stacklayout ist nicht konstant und es gibt auch erstmal keinen Grund anzunehmen, dass es so sein müsste. Wenn du in einer Welt arbeiten musst, in der Interupthandler auf deinem Stack laufen können ist es wichtig sowas zu verstehen, weil es sein kann, dass Speicher, den du scheinbar selbst noch nicht überschrieben hast sporadisch von einem Interrupthandler überschrieben wird.
*Allerdings* funktionieren eine ganze Reihe Optimierungen nur, wenn das Speicherlayout an jedem Punkt zu einem konstanten zur CT bekanntem Layout übersetzt wird. Mir ist nicht ganz klar ob das in C gerade erlaubt ist, aber es gibt Sprachen die sowas können: Wenn du zwei von denen auf dem Stack hast, dann hast du das Problem, dass base und frame pointer erstmal nicht mehr reichen um die zu finden, d.h. du musst dann anfangen auf dem Stack irgendwelche Indexstrukturen anzulegen oder platz für zukünftige noch nicht allokierte variabel lange arrays anzulegen; dasselbe Problem hast du auch mit variabel langen records, wenn es die geben kann. Der vernünftige Weg da raus ist eigentlich immer die auf den Heap zu legen; nichtzuletzt weil man die oft dann doch irgendwann rumreichen muss und das einfach über den Heap schneller ist. In Tyr gibt's das nicht und ich werd's auch nicht einbauen, weil ich den Anwendungsfall nicht sehe; in Ada ist sowas sehr verbreitet und es führt dazu, dass man hunderte Megabyte stacksize für manche Programme braucht. Einfach Unsinn. Kann man auch selbst mit private mmap besser machen. Dafür habe ich aber auch jetzt schon FlatSizedArray (T[n]) und FlatArray(T[]/T*) und Array (std::array, glaube ich) und ArrayBuffer (std::vector). Ist alles nicht dasselbe und die kleinen Unterschiede können was ausmachen, wenn man bis auf's letzte optimieren muss. Aber in der Regel würde ich einfach das nehmen, was sich am natürlichsten anfühlt und effektiv über einen Zeiger über Funktionsgrenzen transportiert wird.
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Biolunar »

Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Krishty »

Für Zeitreisende aus dem Jahr 1995 würde sich das wie ein drogeninduzierter Shitpost lesen. Wow, eine Menge gelernt!
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von starcow »

udok hat geschrieben: 29.11.2022, 10:16 Im Hintergrund wird bei Windows übrigens die Funktion __chkstk (=_alloca) aufgerufen, die den Speicher am Stack reserviert
(Dieselbe Funktion wird übrigens auch beim Anlegen von ganz normalen Arrays am Stack aufgerufen).
Wenn nicht genug Speicher da ist, dann gibt es eine Exception - die den Stack automatisch vergrößert.
Geht das nicht, weil man an die voreingestellte Grenze kommt gibt es eine weitere Exception,
die kann man auch abfangen, und damit eine Fehlerbehandlung machen.
Interessant! Ich wusste nicht mal, dass es sowas wie "Exeptions" unter C gibt! :-)

Biolunar hat geschrieben: 30.11.2022, 12:27 Guter Lesestoff zum Thema VLA: https://stackoverflow.com/questions/225 ... 5#54163435
Scheinen mir ja wirklich sehr präzise und detaillierte Ausführungen zu sein. Leider reicht da mein Level nicht aus, um da in Gänze folgen zu können.
Ich nehme aber soviel mit, dass es bei der Einführung der VLAs in erster Linie darum ging, die Sprach-Konsistenz hinsichtlich bestimmter Edge Cases zu verbessern (?).

Unser Dozent meinte, dass Fälle wie

Code: Alles auswählen

size_t size;
scanf("%zu", &size);
int array[size];
Nicht möglich (resp. UB) wären.
Aber ihr scheint euch da ja alle sicher zu sein! Kennt ihr vielleicht ne Quelle, die ihn möglicherweise überzeugen könnte? (Falls das der Thread auf stackoverflow noch nicht zu leisten vermag).

Auf stackoverflow gibt es dazu ja folgendes Beispiel:

Code: Alles auswählen

size_t n, m;
scanf("%zu %zu", &n, &m);
int (*array)[n][m] = malloc(sizeof *array);
...
Zwar meine ich zu erahnen, was der Code tut, doch wirklich sicher bin ich mir nicht.
Ist das ein 2D array, bestehend aus int-pointern? Wozu wird hier der Dereferenzierungsoperator geklammert? Und die Dereferenzierung von array (bei sizeof) sollte ja eigentlich das erste Element liefern. Also ein int-pointer (8 Bytes auf 64 Bit Plattformen). Ich nehme aber an, reserviert werden hier wohl eher: n * m * Datentypegrösse. Nur, wieso?

Ich habe übrigens nochmals mittels VLAs und scanf arrays erstellt und damit etwas rumexperimentiert. Bei ca. 2,1MB crashte der Prozess jeweils bei mir. Die Grösse des arrays, die den Prozess abstürzen liess, war allerdings nicht immer exakt die selbe.

Gruss, starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
NytroX
Establishment
Beiträge: 358
Registriert: 03.10.2003, 12:47

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von NytroX »

Ist jetzt nicht böse gemeint, aber versuch doch erstmal mit normalen Arrays in C klar zu kommen, bevor du dich mit VLAs beschäftigst.
Das ist kompliziert genug, weil C einfach komplex und schwer zu erklären ist.
Und zudem ist VLA eine optionale Compiler-Erweiterung, die vielleicht gar nicht implementiert ist - ich würde einfach ignorieren, dass es sowas gibt.
z.B. int (*array)[n][m] = malloc(sizeof *array); ist ja nichts mit VLAs, wenn das schon zu kompliziert ist brauchst du mit VLAs und dessen Besonderheiten gar nicht anfangen. :-P

Um den Dozenten zu überzeugen kannst du natürlich die Stelle im C-Standard finden - ich kann das nicht, weil ich nicht einsehe 200 Euro für einen ISO-Standard hinzublättern, der meiner Meinung nach offen sein sollte.
Alternativ tuts vielleicht auch https://en.cppreference.com/w/c/languag ... gth_arrays
Da steht auch alles über Arrays drin.
Bei ca. 2,1MB crashte der Prozess jeweils bei mir.
Naja, das VLA wird ja auf dem Stack angelegt, der ist begrenzt. Wie groß ist denn dein Stack?


Hier nochmal eine kleine Veranschaulichung der Komplexität von Arrays in C (alles "normale" C Arrays):

Code: Alles auswählen

#include <stdio.h>
int main() {
    int a[4];
    f(a);
}

int f(int a[4]) {
  int b[4];
  int c[4][4];
  printf("Größe von a: %d\n", sizeof(a)); //8
  printf("Größe von b: %d\n", sizeof(b)); //16
  printf("Größe von c: %d\n", sizeof(c)); //64
}
Übung:
Warum ist auf x86_64 die Größe von a = 8, von b = 16 und c = 64 ?
Und wie wäre das Ergebnis, wenn die Funktion so aussehen würde:
  1. int f(int a[]){ ... }
  2. int f(int a[static 4]){ ... }
Benutzeravatar
Jonathan
Establishment
Beiträge: 2352
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Jonathan »

NytroX hat geschrieben: 04.12.2022, 21:50 Um den Dozenten zu überzeugen kannst du natürlich die Stelle im C-Standard finden - ich kann das nicht, weil ich nicht einsehe 200 Euro für einen ISO-Standard hinzublättern, der meiner Meinung nach offen sein sollte.
Naja, aber man findet den ja durchaus. Soweit ich mich erinnere gibt es z.B. teilweise ganz offizielle Working Drafts von neuen Standardversionen und dann auch die diffs zur finalen Version - d.h. man kann es sich dann selber ganz offiziell zuammenbasteln. Alternativ findet man natürlich im Internet auch die nicht offiziellen Versionen :D

Als erste Anlaufstelle vlt. das hier: https://stackoverflow.com/questions/816 ... -documents

Aber um Dozenten zu überzeugen: Das klingt so ein bisschen wie ein Erstsemestlerding :D Je länger man in der Uni ist desto mehr versteht man, dass Dozenten auch nicht unbedingt Experten sind. Bzw. dass das, was man so landläufig als Experte bezeichnet auch einfach nicht immer Ahnung oder Recht hat. Und das ist vollkommen ok so.
Ich hätte bis gestern auch behauptet, dass es UB ist, aber wenn mir dann jemand sagt "aaaaactually gibt es auch Variable length Arrays" dann hätte ich halt gesagt "aha, interessant schick mal Link". Irgendwelche Punkte oder Noten beeinflusst sowas in der Regel nicht, es zählt halt der Gesamteindruck und wenn du dich schon mit deinem Dozenten "anlegst" ist der hoffentlich ohnehin positiv (oder du blamierst dich gerade ziemlich :D).
Wenn dein Dozent so ein Ego-Problem hat, dass er dir nicht glauben will, dann vergiss es einfach. Du kannst bei so Diskussionen nicht viel gewinnen, und derartige Menschen würden dir am Ende eher noch einen reinwürgen wenn du zu lange darauf rumreitest.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von starcow »

Danke für deinen Ratschlag und deine Ausführungen Nytro.
Ich hätte jetzt schon gesagt, dass ich die Arrays grundsätzlich soweit ganz gut verstanden habe. Auch die Unterschiede zu Pointern. Was natürlich nicht heisst, dass ich mir einbilde, alles darüber zu wissen! :-)
Aber wenn ich mir die so "üblichen" Kapitelbeiträge in verschiedenen Büchern und Online-Tutorials dazu anschaue, bekomme ich jedenfalls nicht den Eindruck, dass ich elementar etwas noch nicht verstanden hätte.

VLAs waren mir halt neu - finde das einfach interessant.

Deine Übungen sehen spannend aus - werde sie auch sehr gerne versuchen zu beantworten - wenn ichs denn kann! Danke dafür! :-)

Grundsätzlich
Der Parameter a der Funktion f ist kein "echtes" array. Beim Aufruf der Funktion wird die Adresse (Anfangsadresse) des Arrays in einen Pointer vom Typ int konvertiert (int Pointer). sizeof(a) liefert dir also nur die Grösse eines Pointers. Bei einem 64 Bit OS ist diese 8 Byte. Auf einem 32 Bit OS wäre sie allerdings nur 4 Byte.

b ist ein array (kein Pointer) und zwar lokal (Lebensdauer: auto) auf dem Stack mit der Grösse 16 Byte (int entspricht hier 4 Byte: also 4 * 4 = 16).

c ist ein "echtes" 2D Array (also nicht blos ein Array aus Pointern). Es hat 4 Zeilen mit je 4 Spalten (erst die Zeilen, dann die Spalten, wie bei einer Matrix). Das Array liegt auf dem Stack (lückenlos) und weist 16 Elemente auf, von denen jedes 4Byte beansprucht. Also 4^3 = 64 (Byte).

zu 1.
Tatsächlich gäbe es keinen Unterschied. Auch hier ist dieses Array nur ein Pointer. Laut K&R (S. 100) wäre die Syntax int* a zu bevorzugen, da somit sofort klar wäre, dass es sich hierbei nur um einen Pointer und nicht um ein Array handelt (sizeof a liefert auch hier nur die Grösse des Pointers)

zu 2.
Selbe Geschichte wie bei 1.
Die Angabe static 4 ist vielmehr ein versprechen (Hinweis) an den Compiler, dass das array _mindestens_ 4 Elemente aufweist, was ihm (dem Compiler) allenfalls gestattet gewisse Optimierungen vorzunehmen.

NytroX hat geschrieben: 04.12.2022, 21:50 z.B. int (*array)[n][m] = malloc(sizeof *array); ist ja nichts mit VLAs, wenn das schon zu kompliziert ist brauchst du mit VLAs und dessen Besonderheiten gar nicht anfangen. :-P
Hier waage ich mal zu widersprechen :-)
Schon klar: mit malloc reserviere ich dynamisch Speicher auf dem Heap. Doch für den Syntax array[n][m] sind VLAs nötig, da n und m keine Konstanten, sondern Variablen sind. Unter C89 wäre das nicht gegangen. Da ginge nur eine Zahlenkonstante, eine Konstante mittels enum oder eine mittels DEFINE.

Ich lasse mich gerne eines Besseren belehren, falls etwas an meinen Antworten so nicht korrekt ist. :-)

LG, starcow
Jonathan hat geschrieben: 04.12.2022, 23:03 Aber um Dozenten zu überzeugen: Das klingt so ein bisschen wie ein Erstsemestlerding :D Je länger man in der Uni ist desto mehr versteht man, dass Dozenten auch nicht unbedingt Experten sind. Bzw. dass das, was man so landläufig als Experte bezeichnet auch einfach nicht immer Ahnung oder Recht hat. Und das ist vollkommen ok so.
Ich hätte bis gestern auch behauptet, dass es UB ist, aber wenn mir dann jemand sagt "aaaaactually gibt es auch Variable length Arrays" dann hätte ich halt gesagt "aha, interessant schick mal Link". Irgendwelche Punkte oder Noten beeinflusst sowas in der Regel nicht, es zählt halt der Gesamteindruck und wenn du dich schon mit deinem Dozenten "anlegst" ist der hoffentlich ohnehin positiv (oder du blamierst dich gerade ziemlich :D).
Wenn dein Dozent so ein Ego-Problem hat, dass er dir nicht glauben will, dann vergiss es einfach. Du kannst bei so Diskussionen nicht viel gewinnen, und derartige Menschen würden dir am Ende eher noch einen reinwürgen wenn du zu lange darauf rumreitest.
Weise Worte! :-)
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Alexander Kornrumpf
Moderator
Beiträge: 2106
Registriert: 25.02.2009, 13:37

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Alexander Kornrumpf »

Code: Alles auswählen

int (*array)[n][m] = malloc(sizeof *array);
Man kann es fast schon nicht mehr parodieren.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von starcow »

Nach erneutem Überlegen habe ich eine neue Vermutung, die mich soweit schlüssig dünkt.

array ist einfach ein Pointer auf ein 2D array, gefüllt mit int Werten.
Die Klammerung ist dabei nötig, da ich sonst ein 2D array hätte, gefüllt mit int Pointern!

So kriege ich nun die Möglichkeit, ein array auf dem Heap zu verwenden, als wäre es ein "normales" 2D array. Z.b array[4][5]. Und dies dank der neuen Syntax-Möglichkeiten, die die VLAs mitbringen :-).
Verstehe ich das soweit richtig?

Gruss, starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
NytroX
Establishment
Beiträge: 358
Registriert: 03.10.2003, 12:47

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von NytroX »

Perfekt, sehr gut, alles richtig. :-)

Aber die Syntax ist auch sehr merkwürdig mit dem "int (*array)[n][m] = malloc(sizeof *array);", um ehrlich zu sein würde ich sowas nie schreiben.
Funktionspointer sind auch sehr komisch mit der Syntax, aber da führt kein Weg dran vorbei.

Da ja, wie du schon richtig erkannt hast, ein Konstrukt wie "int a[4][4]" als Funktionsparameter gar kein Array ist, sondern ein Pointer, mache ich eigentlich fast nie was mit dieser Syntax, weil es für mich einfach nur verwirrend ist.
Ich würde halt einfach einen Pointer nehmen, und dann mit malloc Platz für x*y*sizeof(typ) reservieren (oder wieviele Dimensionen man halt hat).
Man kann ja den Pointer auch einfach mit Array-Syntax ansprechen, und ich muss mir keine Sorgen um den Stack-Space machen.

Aber ich wusste tatsächlich auch nicht, dass alloca usw. in keinem Standard sind - aber bei C ist halt echt wenig drin, und das was da ist ist meistens dann auch noch schwierig zu benutzen. Nicht so mein Fall :-)

Natürlich ist sowas wie alloca oder VLAs super spannend für Optimierungen in Libraries, also wenn man printf oder so implementiert, zum Beispiel.
Aber bei den Sachen die ich so entwickle wäre es halt eher genau so wie du sagst, ist mal interessant, dass es das gibt/gab, aber das wars auch schon ;-)
Es ist ja leider auch nicht portabler als alloca, also auch in der Verwendung schwierig und man muss es mit #ifdefs absichern, wenn man es nutzen will. Damit ist der Mehrwert aus meiner Sicht für den Benutzer der Sprache sehr begrenzt (d.h. nicht vorhanden).

Trotzdem, auch ich habe wieder was gelernt bei dem Thread. Von daher Daumen hoch :-)
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Krishty »

NytroX hat geschrieben: 05.12.2022, 13:43Funktionspointer sind auch sehr komisch mit der Syntax, aber da führt kein Weg dran vorbei.
Als Tipp für C++ (nicht C):

  using Allocator = void * (size_t); // function expecting a size and returning a void pointer
  Allocator * foo = &malloc; // Funktionszeiger
  Allocator & foo = malloc; // Referenz (oft besser)


Ist gar nicht so komisch.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Biolunar »

Krishty hat geschrieben: 05.12.2022, 22:16
NytroX hat geschrieben: 05.12.2022, 13:43Funktionspointer sind auch sehr komisch mit der Syntax, aber da führt kein Weg dran vorbei.
Als Tipp für C++ (nicht C):

  using Allocator = void * (size_t); // function expecting a size and returning a void pointer
  Allocator * foo = &malloc; // Funktionszeiger
  Allocator & foo = malloc; // Referenz (oft besser)


Ist gar nicht so komisch.
Weiß nicht wie das in C++ ist, aber in C kann man dies tun:

Code: Alles auswählen

// add.c

int add(int x, int y)
{
	return x + y;
}

Code: Alles auswählen

// main.c

#include <stdio.h>

typedef int add_type(int x, int y); // Vermutlich ein ungewöhnliches Konstrukt für die meisten.

int main(void)
{
	int ret;
	
	add_type add; // Hier wird eine richtige Funktion deklariert, die vom Linker gesucht wird!
	ret = add(3, 2);
	printf("add: %d\n", ret);

	add_type* padd = &add; // Normaler Funktionszeiger.
	ret = padd(4, 5);
	printf("padd: %d\n", ret);
}
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von dot »

Krishty hat geschrieben: 05.12.2022, 22:16
NytroX hat geschrieben: 05.12.2022, 13:43Funktionspointer sind auch sehr komisch mit der Syntax, aber da führt kein Weg dran vorbei.
Als Tipp für C++ (nicht C):

  using Allocator = void * (size_t); // function expecting a size and returning a void pointer
  Allocator * foo = &malloc; // Funktionszeiger
  Allocator & foo = malloc; // Referenz (oft besser)


Ist gar nicht so komisch.
Note: Das ist unspecified behavior; du darfst im Allgemeinen nicht einfach so Pointer oder Reference auf eine stdlib Function machen: https://eel.is/c++draft/constraints#namespace.std-6 ;)

Das betrifft übrigens auch so häufig angetroffene Klassiker wie

Code: Alles auswählen

std::transform(str.begin(), str.end(), str.begin(), std::tolower);
Korrekterweise müsste man eigentlich sowas wie

Code: Alles auswählen

std::transform(str.begin(), str.end(), str.begin(), [](char c) { return std::tolower(c); });
machen


Es sei auch erwähnt dass VLAs nur in C erlaubt sind. In C++ gibt es die nicht (gcc hat leider die dumme Angewohnheit, so Zeug wie VLAs by default auch in C++ zu akzeptieren). Und auch in C gibt's VLAs so wirklich eigentlich nur in C99. Seit C11 sind VLAs ein optionales Feature das ein konformer C Compiler nicht unterstützen muss. Grund dafür ist vermutlich wohl der Implementierungsaufwand. Abgesehen davon ist das Feature einfach nur hoffnungslos broken. Das komplette Typesystem wird auf den Kopf gestellt. Manche Typen sind jetzt plötzlich von Laufzeitwerten abhängig. Ja, das heißt der Operand eines sizeof ist nicht mehr unbedingt ein unevaluated Context. Der Operand eines sizeof wird nun nicht nur potentiell ausgewertet sondern potentiell zur Laufzeit ausgewertet. Ja genau, das heißt ein sizeof kann jetzt endlich auch in Dateien schreiben oder Vulkan initialisieren… Mit Ausnahme der Ausnahmefälle natürlich. Es ergeben sich absolut erstaunliche neue Möglichkeiten für undefined und unspecified Behavior noch nie dagewesener Ausmaße. Und die Compilerbugs erst… einfach nur köstlich. Achja, wenn du meinst sizeof zur Laufzeit ist großartig, warte nur bis du unseren neuen alten Freund typedef kennenlernst. Man stelle sich nur mal vor: typedef auf einen Typen, der vom Ergebnis eines HTTP Request abhängig ist… mach das in einer Loop und das typedef definiert in jeder Iteration einen anderen Type… Und die Typen in deinem Code hängen jetzt davon ab ob jemand übers Netzwerkkabel stolpert oder nicht…

Ich hab ehrlich gesagt keine Ahnung wie VLAs jemals in C gelandet sind, das Feature ist dermaßen kaputt dass mir jedes Mal einfach nur der Mund offen stehen bleibt…
Zuletzt geändert von dot am 10.12.2022, 20:52, insgesamt 2-mal geändert.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Krishty »

dot hat geschrieben: 10.12.2022, 16:57Note: Das ist unspecified behavior; du darfst im Allgemeinen nicht einfach so Pointer oder Reference auf eine stdlib Function machen: https://eel.is/c++draft/constraints#namespace.std-6 ;)

Das betrifft übrigens auch so häufig angetroffene Klassiker wie

Code: Alles auswählen

std::transform(str.begin(), str.end(), str.begin(), std::tolower);
Korrekterweise müsste man eigentlich sowas wie

Code: Alles auswählen

std::transform(str.begin(), str.end(), str.begin(), [](char c) { return std::tolower(c); });
machen
Einfach nur krass. Danke!
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Krishty »

dot hat geschrieben: 10.12.2022, 16:57Note: Das ist unspecified behavior; du darfst im Allgemeinen nicht einfach so Pointer oder Reference auf eine stdlib Function machen: https://eel.is/c++draft/constraints#namespace.std-6 ;)
P.S.: Hast du zufällig auch noch eine Erklärung, wie sie darauf gekommen sind?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von dot »

Krishty hat geschrieben: 10.12.2022, 20:21
dot hat geschrieben: 10.12.2022, 16:57Note: Das ist unspecified behavior; du darfst im Allgemeinen nicht einfach so Pointer oder Reference auf eine stdlib Function machen: https://eel.is/c++draft/constraints#namespace.std-6 ;)
P.S.: Hast du zufällig auch noch eine Erklärung, wie sie darauf gekommen sind?
afaik geht's drum dass stdlib Funktionen auch Macros oder direkt Compiler-built-ins sein könnten und daher nicht unbedingt überhaupt sowas wie eine Adresse haben oder sonstwie als Funktionen referenzierbar wären.

Bei std::move beispielsweise wird neuerdings einfach direkt vom Compiler der AST entsprechend umgeschrieben, da gibt es dann nicht wirklich eine Funktion in der Library.
Zuletzt geändert von dot am 10.12.2022, 21:01, insgesamt 2-mal geändert.
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 574
Registriert: 05.07.2003, 11:17

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Lord Delvin »

Krishty hat geschrieben: 10.12.2022, 20:21
dot hat geschrieben: 10.12.2022, 16:57Note: Das ist unspecified behavior; du darfst im Allgemeinen nicht einfach so Pointer oder Reference auf eine stdlib Function machen: https://eel.is/c++draft/constraints#namespace.std-6 ;)
P.S.: Hast du zufällig auch noch eine Erklärung, wie sie darauf gekommen sind?
Wird wie in Tyr sein: Der Compiler kennt sie und macht bei calls was, das nicht zwingend ein Funktionsaufruf ist. Manche "Funktionen" können auch keine sein. Wäre spannend zu sehen, ob sich in der C++-stdlib auch was findet, das unter dem Typ keine *einzelne* Funktion sein kann. So wie C++ gestrickt ist müsste sowas aus der Ecke statische reflection o.ä. kommen, da der ganze lowlevelkram gut repräsentierbar ist. D.h. man kann ein add einfach in eine Funktion wrappen und sich darauf verlassen, dass es geinlined wird. Gibt aber vielleicht gute Gründe auch das nicht zu machen.
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Krishty »

dot hat geschrieben: 10.12.2022, 20:49afaik geht's drum dass stdlib Funktionen auch Macros oder direkt Compiler-built-ins sein könnten
Makros? Wie soll das gehen? Bspw. würde namespace std { #define move(X) __internal_move_helper(X) } verhindern, dass ich irgendeine eigene Funktion oder Variable move nennen und noch erfolgreich linken könnte.

Built-ins in einem Namespace, hm. Kann sein, aber raffen tu ich’s nicht.
dot hat geschrieben: 10.12.2022, 20:49Bei std::move beispielsweise wird neuerdings einfach direkt vom Compiler der AST entsprechend umgeschrieben, da gibt es dann nicht wirklich eine Funktion in der Library.
Fütter mich ruhig mal Zeug zu std::move() – das war ja ein besonders misslungenes Stück, weil man das 30k-Zeilen-#include durch ein einziges static_cast ersetzen kann/konnte :D Einerseits würde mich für meinen eigenen Code interessieren, wie sie die Code Generation dort mit Built-Ins verbessern. Andererseits möchte ich die Horrorgeschichten lesen, die halbwegs vernünftige Compiler-Entwickler dazu drängen, so hart mit der Sprachsymmetrie zu brechen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Array-Grösse zur Laufzeit festlegen?

Beitrag von Krishty »

Krishty hat geschrieben: 10.12.2022, 21:32Fütter mich ruhig mal Zeug zu std::move()
Visual C++ tut das jetzt auch: https://devblogs.microsoft.com/cppblog/ ... -we-did-it
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten