Untypischer Laufzeitfehler durch malloc()
-
@john-0 sagte in Untypischer Laufzeitfehler durch malloc():
Unter IX wird das Thema Libraries etwas anders gehandhabt als unter Windows.
Ja. Totaaaaal anders. Statische Libraries und dynamisch geladene. Gaaaanz anders.
-
Danke @DirkB @john-0 @Swordfish für die Antworten. Das Thema Librarys ist etwas komplex und ich finde mich nicht zurecht darin. Wenn ich @john-0 richtig verstanden habe gibt es dynamische *.so und statische *.a librarys auf meinem System. Wenn ich dynamische libs einbinde, müssen die auf dem Zielsystem zur Laufzeit vorhanden sein und bei statischen nicht? da ich sie "fest eincompiliert" habe?
Wenn ich jetzt für ein Win-Ziel crosscompilieren will, was muss ich da bezüglich der Librarys beachten? Welche Hürden gibt es da?
Die von @DirkB erwähnten DLL's sind das Win-gegenstück zu den *.so dateien? Wenn ja, wie heiseßen die statischen .*a Dateien auf Win?@Swordfish Ist dein Beitrag ironisch, oder stimmst du @DirkB energisch zu, bezüglich Win/IX-librarys
-
@Swordfish sagte in Untypischer Laufzeitfehler durch malloc():
Ja. Totaaaaal anders. Statische Libraries und dynamisch geladene. Gaaaanz anders.
Wie ich immer diese geistreichen Anmerkungen liebe. Dir ist hoffentlich bewusst, dass es unter UNIX auch statisch shared Libraries gab bzw. von den Toolchains zum Teil noch unterstützt werden? Dir ist hoffentlich bewusst, dass man nicht jede UNIX Plattform das Laden von dynamic shared Libraries in das laufende Programm unterstützt? Man muss auf diesen Plattformen ein anderes DSO Format erzeugen, damit man das machen kann. macOS ist wohl der bekannteste Vertreter. Aber ja doch, es gibt keine Unterschiede.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Wenn ich jetzt für ein Win-Ziel crosscompilieren will, was muss ich da bezüglich der Librarys beachten? Welche Hürden gibt es da?
Daß die benötigten Libraries für die Zielplatform verfügbar sind oder gebaut werden können oder etwas halbwegs kompatibles verfügbar ist. (Beispiel mit PDCurses unten.)
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Die von @DirkB erwähnten DLL's sind das Win-gegenstück zu den *.so dateien? Wenn ja, wie heiseßen die statischen .*a Dateien auf Win?
Unter Windows enden Statische- und Importlibraries auf .lib.
Was fällt Dir auf wenn Du Deinen und meinen Code vergleichst?
#include <errno.h> #include <stdbool.h> #include <stddef.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #if defined _MSC_VER # include <windows.h> # undef MOUSE_MOVED # include "../PDCurses/curses.h" # define resizeterm resize_term # if defined(_WIN64) # error "PDCurses missing for x64 :(" # elif defined(_WIN32) # ifdef _DEBUG # pragma comment(lib, "../pdcurses/wincon/pdcursesd.lib") # else # pragma comment(lib, "../pdcurses/wincon/pdcurses.lib") # endif # endif #elif defined __linux__ # include <unistd.h> # include <curses.h> # include <string.h> # define Sleep(x) usleep((x) * 1000) #endif void print_usage(char const *program_name) { printf("Usage: %s [WIDTH] [HEIGHT]\n\n", program_name); } bool str2int(char const *str, int *number) { errno = 0; char *endptr; *number = strtol(str, &endptr, 10); return errno != ERANGE && *endptr == '\0'; } void curses_init() { initscr(); refresh(); noecho(); leaveok(stdscr, true); nodelay(stdscr, true); keypad(stdscr, true); curs_set(0); } typedef struct coord_tag { int x; int y; } coord_t; typedef enum direction_tag { DIRECTION_RIGHT = KEY_RIGHT, // +x DIRECTION_LEFT = KEY_LEFT, // -x DIRECTION_DOWN = KEY_DOWN, // +y DIRECTION_UP = KEY_UP // -y } direction_t; enum { INITIAL_LENGTH = 3, GROWTH_DELTA = 8, DELAY = 100 // ms }; typedef struct snake_tag { coord_t *body; size_t length; direction_t direction; bool is_alive; size_t new_length; int delay; } snake_t; coord_t coord_create(int x, int y) { coord_t coord = { x, y }; return coord; } bool snake_create(snake_t *snake, coord_t initial_position, direction_t direction) { coord_t *body = malloc(sizeof *body); if (!body) return false; snake->body = body; snake->body[0] = initial_position; snake->length = 1; snake->direction = direction; snake->is_alive = true; snake->new_length = INITIAL_LENGTH; snake->delay = DELAY; return true; } bool snake_in_body(snake_t const *snake, coord_t position, bool include_head) { for (size_t i = include_head ? 0 : 1; i < snake->length; ++i) if (snake->body[i].x == position.x && snake->body[i].y == position.y) return true; return false; } bool snake_is_alive(snake_t *snake) { coord_t head = snake->body[0]; if (!head.x || !head.y || head.x == COLS - 1 || head.y == LINES - 1) snake->is_alive = false; else if (snake_in_body(snake, head, false)) snake->is_alive = false; return snake->is_alive; } void snake_update_direction(snake_t *snake, direction_t new_direction) { if (new_direction != DIRECTION_RIGHT && new_direction != DIRECTION_LEFT && new_direction != DIRECTION_DOWN && new_direction != DIRECTION_UP) return; if (snake->direction == new_direction) return; if (snake->direction == DIRECTION_RIGHT && new_direction == DIRECTION_LEFT || snake->direction == DIRECTION_LEFT && new_direction == DIRECTION_RIGHT || snake->direction == DIRECTION_UP && new_direction == DIRECTION_DOWN || snake->direction == DIRECTION_DOWN && new_direction == DIRECTION_UP) { snake->is_alive = false; return; } snake->direction = new_direction; } bool snake_move(snake_t *snake) { coord_t new_head_position = snake->body[0]; coord_t old_tail_position = snake->body[snake->length - 1]; switch (snake->direction) { case DIRECTION_RIGHT: ++new_head_position.x; break; case DIRECTION_LEFT: --new_head_position.x; break; case DIRECTION_DOWN: ++new_head_position.y; break; case DIRECTION_UP: --new_head_position.y; break; } mvaddch(new_head_position.y, new_head_position.x, '*'); for (size_t i = snake->length - 1; i; --i) snake->body[i] = snake->body[i - 1]; snake->body[0] = new_head_position; if (snake->length < snake->new_length) { coord_t *new_body = realloc(snake->body, (snake->length + 1) * sizeof(*new_body)); if (!new_body) return false; snake->body = new_body; snake->body[snake->length++] = old_tail_position; } else mvaddch(old_tail_position.y, old_tail_position.x, ' '); refresh(); return true; } void snake_grow(snake_t *snake) { snake->new_length = snake->length + GROWTH_DELTA; } bool snake_try_eat(snake_t const *snake, coord_t food) { return snake->body[0].x == food.x && snake->body[0].y == food.y; } void snake_delay(snake_t const *snake) { int delay = snake->delay; if (snake->direction == DIRECTION_DOWN || snake->direction == DIRECTION_UP) delay = (int)(delay * 1.4); Sleep(delay); } void snake_delete(snake_t *snake) { free(snake->body); } coord_t food_create(snake_t const *snake, int max_x, int max_y) { coord_t food; do food = coord_create(rand() % (max_x - 2) + 1, rand() % (max_y - 2) + 1); while (snake_in_body(snake, food, true)); return food; } int main(int argc, char **argv) { int desired_width = 80; int desired_height = 25; if (argc > 3 || argc > 1 && !str2int(argv[1], &desired_width) || argc > 2 && !str2int(argv[2], &desired_height)) { print_usage(argv[0]); return EXIT_FAILURE; } curses_init(); #ifdef __linux__ { char buffer[80]; sprintf(buffer, "resize %3d %3d > /dev/null 2>&1", desired_height, desired_width); system(buffer); } #endif if (resizeterm(desired_height, desired_width) == ERR) { endwin(); fprintf(stderr, "Couldn't resize Terminal to %d x %d :(\n\n", desired_width, desired_height); return EXIT_FAILURE; } snake_t snake; if (!snake_create(&snake, coord_create(COLS / 2, LINES / 2), DIRECTION_RIGHT)) { endwin(); fputs("Not enough memory :(\n\n", stderr); return EXIT_FAILURE; } box(stdscr, 0, 0); srand((unsigned) time(NULL)); coord_t food = food_create(&snake, COLS, LINES); mvaddch(food.y, food.x, 'O'); do { snake_update_direction(&snake, getch()); if (!snake_move(&snake)) { snake_delete(&snake); endwin(); fputs("Not enough memory :(\n\n", stderr); return EXIT_FAILURE; } if (snake_try_eat(&snake, food)) { snake_grow(&snake); food = food_create(&snake, COLS, LINES); mvaddch(food.y, food.x, 'O'); } snake_delay(&snake); } while (snake_is_alive(&snake)); snake_delete(&snake); endwin(); }
-
@Swordfish
super Danke für die Arbeit, ich schau mir morgen /also heute am Tage an den code an
-
@Swordfish Ich fange grade an deinen code zu analysieren. Der erste unterschied der mir auffällt ist die bedingte Compilierung. Bei mir lässt es sich nicht compilieren
gcc -o test test.c /usr/bin/ld: /tmp/ccHS05xB.o: in function `curses_init': test.c:(.text+0xbe): undefined reference to `initscr' /usr/bin/ld: test.c:(.text+0xc5): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0xcd): undefined reference to `wrefresh' /usr/bin/ld: test.c:(.text+0xd2): undefined reference to `noecho' /usr/bin/ld: test.c:(.text+0xd9): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0xe6): undefined reference to `leaveok' /usr/bin/ld: test.c:(.text+0xed): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0xfa): undefined reference to `nodelay' /usr/bin/ld: test.c:(.text+0x101): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x10e): undefined reference to `keypad' /usr/bin/ld: test.c:(.text+0x118): undefined reference to `curs_set' /usr/bin/ld: /tmp/ccHS05xB.o: in function `snake_is_alive': test.c:(.text+0x275): undefined reference to `COLS' /usr/bin/ld: test.c:(.text+0x285): undefined reference to `LINES' /usr/bin/ld: /tmp/ccHS05xB.o: in function `snake_move': test.c:(.text+0x425): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x42f): undefined reference to `wmove' /usr/bin/ld: test.c:(.text+0x43b): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x448): undefined reference to `waddch' /usr/bin/ld: test.c:(.text+0x534): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x53e): undefined reference to `wmove' /usr/bin/ld: test.c:(.text+0x54a): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x557): undefined reference to `waddch' /usr/bin/ld: test.c:(.text+0x55e): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x566): undefined reference to `wrefresh' /usr/bin/ld: /tmp/ccHS05xB.o: in function `main': test.c:(.text+0x7d9): undefined reference to `resizeterm' /usr/bin/ld: test.c:(.text+0x7e3): undefined reference to `endwin' /usr/bin/ld: test.c:(.text+0x81a): undefined reference to `LINES' /usr/bin/ld: test.c:(.text+0x82b): undefined reference to `COLS' /usr/bin/ld: test.c:(.text+0x863): undefined reference to `endwin' /usr/bin/ld: test.c:(.text+0x894): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x8c1): undefined reference to `wborder' /usr/bin/ld: test.c:(.text+0x8dc): undefined reference to `LINES' /usr/bin/ld: test.c:(.text+0x8e2): undefined reference to `COLS' /usr/bin/ld: test.c:(.text+0x90d): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x917): undefined reference to `wmove' /usr/bin/ld: test.c:(.text+0x923): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x930): undefined reference to `waddch' /usr/bin/ld: test.c:(.text+0x937): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0x93f): undefined reference to `wgetch' /usr/bin/ld: test.c:(.text+0x97c): undefined reference to `endwin' /usr/bin/ld: test.c:(.text+0x9d8): undefined reference to `LINES' /usr/bin/ld: test.c:(.text+0x9de): undefined reference to `COLS' /usr/bin/ld: test.c:(.text+0xa09): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0xa13): undefined reference to `wmove' /usr/bin/ld: test.c:(.text+0xa1f): undefined reference to `stdscr' /usr/bin/ld: test.c:(.text+0xa2c): undefined reference to `waddch' /usr/bin/ld: test.c:(.text+0xa66): undefined reference to `endwin' collect2: error: ld returned 1 exit status
-
Das ist ein linker fehler und kein compiler fehler du musst die lib angeben (vermutlich -lncurses)
-
@EL-europ
Mein Fehler. hab -lncurses vergessen. programm lässt sich fehlerfrei compilieren
-
@firefly Ja, genau. Danke
-
@Swordfish
mit "#if defined var" fragt der Präprozessor wo genau nach ob die Variable var gesetzt ist?
mit "#pragma com(lib, 'str')" werden Compileroptionen gesetzt. Welche Bedeutung haben com, lib und str
mit "#define Sleep..." wird Sleep(x) durch usleep((x) * 10000) ersetzt. Gibt es in win eine Funktion namens "Sleep(int x)"? oder wie funktioniert das delay bei compilierung auf win?Bei der Analyse hab ich curses ausgelassen, das ist ein eigenes Thema denke ich, und komme zu folgendem Ergebnis.
Dein Code scheint Objektorientiert zu sein?
ich hab vergessen den Speicher wieder frei zu gebenBezüglich enum:
Der mir ersichtliche Vorteil ist das ich sie im Editor "zusammenklappen" kann.
Jürgen Wolf schreibt das Enumerationen mit Bezeichner, im Gegensatz zu #define vom Debugger symbolisch dargestellt werden!
Was meint er damit?bezüglich size_t in snake_t.lenght und snake_t.new_lenght
was ist hier der Unterschied zu int, oder warum benutzt du size_t statt int?Was mir hier unbedeutend ist (curses) aber dich vielleicht interessiert
Das Resize des Terminal funktioniert bei mir nicht
Wenn ich curses nicht initialisiere und dem restlichen code nach "if(resizeterm.." auskommentiere,
funktioniert die Ausgabe das das Terminal nicht resized werden konnte.
Wenn ich das komplette Programm mit werten die zu resize führen aufrufe, wird nicht resized,
das Spiel startet, aber was über rechts hinausgeht zeichnet er dann am linken Rand weiter.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
mit "#if defined var" fragt der Präprozessor wo genau nach ob die Variable var gesetzt ist?
Der Präprozessor kennt keine in C deklarierten Variablen.
defined _MSC_VER
gibt1
wenn das Präprozessorsymbol_MSC_VER
definiert wurde. Das ist der Fall wenn mit dem Microsoft C++-Compiler übersetzt wird.@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
mit "#pragma com(lib, 'str')" werden Compileroptionen gesetzt. Welche Bedeutung haben com, lib und str
https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
mit "#define Sleep..." wird Sleep(x) durch usleep((x) * 10000) ersetzt. Gibt es in win eine Funktion namens "Sleep(int x)"?
Genau. Und ja.
https://docs.microsoft.com/de-de/windows/win32/api/synchapi/nf-synchapi-sleep
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Bezüglich enum:
Der mir ersichtliche Vorteil ist das ich sie im Editor "zusammenklappen" kann.
Jürgen Wolf schreibt das Enumerationen mit Bezeichner, im Gegensatz zu #define vom Debugger symbolisch dargestellt werden!
Was meint er damit?Erster Beweggrund ist Namen zu haben anstatt im ganzen Code Magic Numbers zu verteilen. Zweitens hat man dadurch auch einen Typ der dabei hilft zu dokumentieren welche Werte (bzw. symbolische Konstanten) für welche Variablen sinnvoll sind. Was Wolf meint? Wahrscheinlich daß man eben statt den Zahlen einen Bezeichner sieht.
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
bezüglich size_t in snake_t.lenght und snake_t.new_lenght
was ist hier der Unterschied zu int, oder warum benutzt du size_t statt int?Für
size_t
ist garantiert daß der Typ groß genug für jedes mögliche Objekt im Speicher ist.@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Was mir hier unbedeutend ist (curses) aber dich vielleicht interessiert
Das Resize des Terminal funktioniert bei mir nichtJa, bei mir auch nicht. Hab' es mit (u)rxvt und xterm probiert.
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Dein Code scheint Objektorientiert zu sein?
Bingo. Mir hätte zwar die Erkenntnis gereicht daß ich ohne globale Variablen auskomme und jede Funktion eine klare Aufgabe hat, aber ...
Siehst Du die Vorteile?
-
@Swordfish
Also kann ich mit "if defined" nur Eigenschaften des eingesetzten Compilers abfragen?
Ja, ich glaube du hast alles was geht in Funktionen ausgelagert
Für mich als Anfänger wird der Code dadurch schwerer lesbar, aber ich will ja was lernen und habe den Autor an der Seite. Ich bin den Code Zeile für Zeile durch gegangen, aber weshalb der komplette body gezeichnet wird kann ich noch nicht nachvollziehen. Da ist mir dann die Luft ausgegangen nach dem ich alle anderen zurückgestellten Fragen (ausser curses) geklärt habe
Danke das du dir die Mühe gemacht hast und einen kompletten Code zum Nachvollziehen geschrieben hast. Das hilft mir sehr
-
@Swordfish
Ich muss mich korrigieren
Dein Code ist viel lesbarer als meiner. Ohne die Kommentare würde mein Code völlig unleserlich sein, man bräuchte Notizen und müsste sich viel mehr im Gedächtnis behalten; deiner ist auch ohne Kommentare lesbar. Vielleicht schwierig als Anfänger wegen den vielen Funktionen, aber ohne Kommentare, Notizen usw... lesbar
-
@Swordfish
Ach, eine Frage hab ich vergessen:for (size_t i = snake->length - 1; i; --i)
Weshalb funktioniert diese Schleife obgleich die Abbruchbedingung lediglich die Zählvariable 'i' ist?
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Weshalb funktioniert diese Schleife obgleich die Abbruchbedingung lediglich die Zählvariable 'i' ist?
Der mittlere Ausdruck einer
for
Schleife wird als Bedingung ausgewertet. Die Regel dabei ist dass 0 alsfalse
gilt und alle anderen Werte alstrue
.D.h.
i
als Laufbedingung ist gleichbedeutend miti != 0
.Das selbe gilt z.B. auch in
if
Statements. Alsoif (i)
ist gleichbedeutend mitif (i != 0)
. Bei Zeigern hast du das vermutlich schon gesehen, da schreibt man gerne nurif (pointer)
stattif (pointer != 0)
oderif (pointer != NULL)
.Bei Integers finde ich persönlich es aber komisch. Kann man machen wenn 0 für "nichts" steht, z.B. wenn man in einem Integer einzelne Bits als Flags für etwas verwenden und dann mit
if (flags)
prüft ob irgend ein Flag gesetzt ist - da finde ich es noch OK. Wenn 0 aber einfach nur für die Zahl 0 steht wie in diesem Beispiel, würde ich eheri != 0
schreiben.ps: Ganz furchtbar finde ich
if (strcmp(a, b))
. Diese Bedindung ist wahr wennstrcmp(a, b)
etwas anderes als 0 zurückgibt, und das tut sie wenn die Strings unterschiedlich sind. Da kann man sich beim schnell drüberlesen leicht vertun und fälschlicherweise annehmen dass der Block betreten wird wenn die Strings gleich sind.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
@Swordfish
Also kann ich mit "if defined" nur Eigenschaften des eingesetzten Compilers abfragen?Der C Präprozessor überprüft damit nur, ob eine Variable des Präprozessors definiert wurde. Beispiel
#include <stdio.h> #include <stdlib.h> int main () { #ifdef LINUX printf("Linux\n"); #else printf("anything else\n"); #endif return EXIT_SUCCESS; }
#ifdef
ist die Kurzform von#if defined
. Man kann auf der Kommandozeile beim Übersetzen mit dem gcc "-D" + "NAME" angeben, so dass die Variable definiert wird:gcc -DLINUX example.c -o example
übersetzt den Code in der einen Variante und ohne in der anderen.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Ohne die Kommentare würde mein Code völlig unleserlich sein, man bräuchte Notizen und müsste sich viel mehr im Gedächtnis behalten;
Dann weißt Du jetzt ja warum ich
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Aber Ich glaube die curses kommt mit schnellen Tastenanschlägen nicht so klar. wenn ich im "Automove-modus" eine Zeit (ca. 3-5min) lang spiele, stürzt das Programm einfach ab. Kannst du mir nochmal Helfen?
nicht beantworten wollte ^^
-
@john-0
Das Funktioniert so wie du schreibst. Doch in dem Übungsprogramm
steht '#if defined MSC_VER ... #elif defined linux' und ich hab kein -D__linux_ beim kompilieren gesetzt. Aber er hat den Code nach linux eingesetzt. Gibt es irgend eine Datei in welcher der Präprozässor standardmäßig Variablen wie z.B. _MSC_VER oder linux abfragt oder hat er die "in sich"? er muss ja irgendwo linux bei mir gefunden haben, sonst hätte der Aufruf der Sleep-Funktion beim compilieren einen Fehler ausgelöst.
-
@Swordfish
Ja, beim lernen von c tun sich bei mir mehrere Baustellen gleichzeitig auf. Ist ne ganz andre Sache als python. Der Compiler hat wohl fast den gleichen Einfluss wie der Code.
Eine Bitte habe ich noch. Erklär mir bitte diesen Schleifenkopf aus deinem Programmfor (size_t i = snake->length - 1; i; --i)
Hier ist doch die Abbruchbedingung gleich der Zählvariable, wieso Funktioniert die Schleife?
-
@EL-europ Denk dir an der Stelle ein
i != 0
dann solltest du darauf kommen.Mehr steht bei https://www.c-plusplus.net/forum/topic/352442/untypischer-laufzeitfehler-durch-malloc/56