Forum: PC-Programmierung Anfängerproblem mit C


von Holger (holger_p2)


Lesenswert?

Hallo,

ich bin blutiger Anfänger in C und habe gleich ein Verständnis Problem
1
void fn1(int *j){
2
int i;
3
i = *j;  // i ist 123 ok
4
*j = *j + 1; // der inhalt der Speicherstelle auf die j zeigt + 1 ok
5
i = *j;  // i ist 124 ok
6
j++;  // adresse +4 ok
7
*j++; // adresse +4 warum?
8
i = *j;  // i ist irgendwas ok
9
}
10
11
int main(void) {
12
  int k=123;
13
  fn1(&k);
14
  return 0;
15
}

Warum wird bei *j++ die Adresse erhöht und nicht der Inhalt der 
Speicherstelle?

Danke im voraus
von Hans W. (hanswieland)


Lesenswert?

Holger schrieb:
> Warum wird bei *j++ die Adresse erhöht und nicht der Inhalt der
> Speicherstelle?

Weil ++ eine höhere Rangfolge als * hat.
https://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t
von Michael B. (laberkopp)


Lesenswert?

Holger schrieb:
> Warum wird bei *j++ die Adresse erhöht und nicht der Inhalt der
> Speicherstelle?

(*j)++;

Adresse um 4 erhöhen weil dein int 4 byte gross ist und +1 zum nächsten 
int führen soll (den es hier nicht gibt).
von Holger (holger_p2)


Lesenswert?

(*j)++;
getestet und funktioniert.

Danke für die schnelle Antwort
von Rolf (rolf22)


Lesenswert?

Holger schrieb:
> (*j)++;
> getestet und funktioniert.

Am besten gewöhnst du dir unnötig klammernsparende Schreibweisen gar 
nicht erst an. Wenn du nicht tagtäglich immer nur programmierst, 
unterlaufen dir sonst leicht mal Fehler. Oder du verlierst Zeit, weil du 
beim Suchen von (anderen) Fehlern immer wieder mal 
überlegen/nachschlagen musst, ob nicht diese Schreibweise der gesuchte 
Fehler ist.

Stichwort: Defensive Codierung.

Der Compiler übersetzt ohnehin unabhängig von der Schreibweise, es spart 
also nichts.
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Holger schrieb:
> i = *j;  // i ist irgendwas ok

Ist nicht ok, ist "undefined behavior" (UB) und kann irgendwas bewirken, 
z.B. Programmabsturz. Oder der Compiler entfernt einfach die 
main()-Funktion komplett, weil er davon ausgehen darf dass UB nie 
auftritt und somit die main() Funktion sowieso nie aufgerufen wird, weil 
sie immer zu UB führt. Das gilt auch für Lesezugriffe.
von Harald K. (kirnbichler)


Lesenswert?

Niklas G. schrieb:
> Ist nicht ok, ist "undefined behavior" (UB) und kann irgendwas bewirken,
> z.B. Programmabsturz.

Aber nur im Kontext der von Dir nicht zitierten vorangegangenen 
Codezeilen.

Für sich alleine betrachtet ist die von Dir zitierte Zeile 8 vollkommen 
legitimer Code, nämlich 'ne simple Pointerdereferenzierung.

"Kriminell" wird es durch die Zeilen 6 und 7 des Codes aus dem 
Eröffnungsthread, die den Pointer auf etwas anderes zeigen lassen als 
beim Aufruf der Funktion, der der Pointer übergeben wurde.
von Georg W. (gewe)


Lesenswert?

j++;  // adresse +4 ok

Ich dachte sizeof(INT) ist plattformabhängig und nicht generell 4.

Wir programmieren SPSen in ANSI C und da ist INT nur 2 byte groß.
von Harald K. (kirnbichler)


Lesenswert?

Georg W. schrieb:
> Ich dachte sizeof(INT) ist plattformabhängig und nicht generell 4.

Ist es auch nicht.

Man kann es getrost als Fehler betrachten, hier "generell" anzunehmen.

Auf 8- oder 16-Bit-Systemen ist ein int üblicherweise 16 Bit groß, auf 
32-Bit-Systemen ist er üblicherweise 32 Bit groß, auf 64-Bit-Systemen 
ist er meistens auch 32 Bit groß, kann aber auch 64 Bit groß sein.

Georg W. schrieb:
> Wir programmieren SPSen in ANSI C und da ist INT nur 2 byte groß.

Das liegt nicht an "Ansi-C" (das nennt man heutzutage C89), sondern 
daran, daß da entweder 8- oder 16-Bit-CPUs drinstecken.
von Udo K. (udok)


Lesenswert?

Harald K. schrieb:
>> Ich dachte sizeof(INT) ist plattformabhängig und nicht generell 4.
>
> Ist es auch nicht.

Wenn wir schon beim klugscheissen sind...

INT ist immer 4 Bytes.  Das ist ein typedef in Windows.
von Oliver S. (oliverso)


Lesenswert?

Harald K. schrieb:
> Das liegt nicht an "Ansi-C" (das nennt man heutzutage C89), sondern
> daran, daß da entweder 8- oder 16-Bit-CPUs drinstecken.

Das liegt nur und ausschliesslich am ABI der toolchain. Natürlich wird 
da in der Regel Rücksicht auf die Architektur genommen, aber ein Muss 
ist das nicht.

Oliver
von Nick (b620ys)


Lesenswert?

Udo K. schrieb:
> Wenn wir schon beim klugscheissen sind...
>
> INT ist immer 4 Bytes.  Das ist ein typedef in Windows.

Wenn wir schon beim Klugscheissen sind, hast Du dich grad selbst 
widerlegt.

sizeof(int) ist Plattformabhängig. Und bei Windows halt grad mal 4.
int32_t ist plattformunabhängig, nicht zufälligerweise immer und überall 
4 Byte  und das soll man auch verwenden
von Udo K. (udok)


Lesenswert?

Lern mal lesen.
von Nick (b620ys)


Lesenswert?

Udo K. schrieb:
> Lern mal lesen.

Von dir?

BTW:
Ich war es nicht, der mit INT dahergekommen ist. Die Frage des TO war 
plattformunabhängig gestellt.

BTW 2:
Aber es gibt auf µC genug Kasperln, die dem Beitrag 
Beitrag "Re: Anfängerproblem mit C" Minuspunkte geben.
Einer der Pluspunkte war von mir.
von K. L. (trollen) Benutzerseite


Angehängte Dateien:

Lesenswert?

Die ganze Streiterei um C und seine Regeln und Definitionen erinnert 
mich einfach immer wieder an dieses Meme. Egal wie perfekt jemand C 
kann, irgendwann übersieht er was und schießt sich dann voll selbst ins 
Knie. Ohne Ausnahme.

Grüße von einem Rust-Coder, der sich lange genug mit der C-Grütze 
rumgeschlagen hat und jetzt die Show genießt.
von Frank D. (Firma: LAPD) (frank_s634)


Lesenswert?

Das sind aber Anfängerprobleme, solche gibt es in jeder Sprache wenn man 
noch keine Ahnung hat.
von Rbx (rcx)


Lesenswert?

Speichernavigation sollte man erst weiter hinten anfangen. Das ist 
besser, denn da kommen viele Anfänger durcheinander, wenn die nicht die 
Grundlagen erarbeitet hatten.
Ich hatte damals auch Probleme (weil: da kommt doch vieles auf einmal 
auf einen zu) und so brauchte ich so um die 2-3 Wochen, um da lockerer 
draufzuschauen.
Vielleicht ist es besser, erstmal mit Stackoverflow (nicht die 
Internetseite) und gdb in die Speichergeschichte einzusteigen. Kann 
jedenfalls auch hilfreich sein.
Hinsichtlich der Sonderzeichen ist das Erlenkötterbuch gut - da muss man 
aber bei der Stange bleiben, damit man die Zusammenhänge behalten kann.
von Walter S. (avatar)


Lesenswert?

Niklas G. schrieb:
>> i = *j;  // i ist irgendwas ok
>
> Ist nicht ok, ist "undefined behavior" (UB) und kann irgendwas bewirken,
> z.B. Programmabsturz. Oder der Compiler entfernt einfach die
> main()-Funktion komplett, weil er davon ausgehen darf dass UB nie
> auftritt und somit die main() Funktion sowieso nie aufgerufen wird, weil
> sie immer zu UB führt. Das gilt auch für Lesezugriffe.

das glaube ich erst Mal nicht (ohne es zu wissen):
wenn der Compiler main übersetzt, weiß er doch nicht dass in fn1 ein 
undefined behavior auftritt (fn1 könnte ja auch in einem anderen File 
sein)
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Walter S. schrieb:
> Compiler main übersetzt, weiß er doch nicht dass in fn1 ein undefined
> behavior auftritt (fn1 könnte ja auch in einem anderen File sein)

Ich hab ja nicht gesagt dass der Compiler das UB erkennen muss. Aber 
wenn er es erkennt, darf er das Programm beliebig verunstalten ohne den 
C-Standard zu verletzen. Der Standard verlangt nicht vom Compiler, 
fehlerhaften Code irgendwie sinnvoll zu übersetzen.

Wenn fn1 in der selben Datei steht wie hier im Beispiel, sieht der 
Compiler was darin passiert. Wenn's eine andere Datei ist sieht er es 
auch, wenn LTO aktiviert ist.
von Udo K. (udok)


Lesenswert?

Nick schrieb:
> Von dir?
>
> BTW:
> Ich war es nicht, der mit INT dahergekommen ist. Die Frage des TO war
> plattformunabhängig gestellt.

Ja, offensichtlich von mir :-)

INT gibt es im C-Standard nicht.
C unterscheidet zwischen Groß- und Kleinschreibung.

INT ist ein in Millionen von Zeilen verwendetes Typedef, das immer 
4-Bytes hat.
von Rick (rick)


Lesenswert?

Udo K. schrieb:
> INT ist ein in Millionen von Zeilen verwendetes Typedef, das immer
> 4-Bytes hat.
Quatsch. Du kennst nur nicht genügend Prozessorarchitekturen:
1
#include <stdio.h>      // printf
2
3
void main( void)
4
{
5
    int i, j;
6
7
    i = 0;
8
    j = 1;
9
    while( j > i)
10
    {
11
        i++;
12
        j++;
13
    }
14
    printf( "%d %d\n", i, j);
15
}
1
32767 -32768
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Und wo ist da INT?

Übrigens word das printf u.U. nie erreicht (Signed Overflow).
: Bearbeitet durch User
von Norbert (der_norbert)


Lesenswert?

Walter S. schrieb:
> das glaube ich erst Mal nicht (ohne es zu wissen):
> wenn der Compiler main übersetzt, weiß er doch nicht dass in fn1 ein
> undefined behavior auftritt (fn1 könnte ja auch in einem anderen File
> sein)

fn1() übergibt einen Zeiger auf einen int Wert. NUR EINEN!
Wenn nun dieser Zeiger inkrementiert wird:
1
j++;  // adresse +sizeof(POINTER)
dann zeigt j hinter den angedachten int Wert.
Also ist:
1
i = *j;
ein Zugriff über einen ungültigen Zeiger.
von Nick (b620ys)


Lesenswert?

Udo K. schrieb:
> Ja, offensichtlich von mir :-)

Ich weiß. :-)

Udo K. schrieb:
> INT ist ein in Millionen von Zeilen verwendetes Typedef, das immer
> 4-Bytes hat.

Wo ist das immer 4 Btes groß?
Bei dir? In wie vielen Milliarden Zeilen C-Code NICHT?

Mir ist schon klar, dass das K&R-C unzulänglich ist/war und dass von 
dort die Ursprünge des Gewurstles, das sich über Dekaden hinzieht, 
herkommt.
"Inzwischen" kann man aber die Typen verwenden, die klar in der Größe 
definiert sind. Und das sollte man auch.

Bitte dazu mal <stdint.h> lesen, bzw. Kommentare/Erklärungen dazu.

Anekdote:
Ich hatte mal mit dem Propeller von Parallax rumgespielt. In 
interessanter 32 Bit Prozessor mit einer verkorksten Sprache "Spin".
Da war ein Integer Typ "word". Irgendwann wundere ich mich, warum der 
nur 16 Bit groß ist und frag im Forum nach. Bis dann der Entwickler des 
Propeller (Gracey ?) geantwortet hat, dass "word" immer 16 Bit lang ist. 
Auf die Frage woher denn die Definition kommt:
Er hat den Compiler für Spin in Assember (total gaga, aber Respekt für 
die Arbeit) 8086 (jedenfalls ein 16-Bitter) geschrieben und da ist das 
halt ein word.
Den Compiler mussten sie komplett neu schreiben, ASM ist nicht 
sonderlich portabel. Spin wurde dann um C ergänzt, der Propeller 
verschwindet so langsam in der Versenkung. Bis auf eine extrem 
engagierte Fan-Gemeinde.

long, double, long long, unsigned char, das ist völlig ballaballa.
Leute, schreibt euren code plattformunabhängig und leserlich.

Ah, und zum Rust-Kommentar:
Ja, da geb ich dir Recht. Der Designer hatte wohl genug unter C 
gelitten. Ich warte noch darauf, dass Rust endlich mal auf µC 
implementiert wird. Der eine STM32 (oder was) ist reichlich wenig um 
sich da drauf einzulassen. Ich wäre aber sofort dabei! Hab aber Rust 
seit zwei Jahren nicht mehr angefasst.
von Udo K. (udok)


Lesenswert?

Norbert schrieb:
> fn1() übergibt einen Zeiger auf einen int Wert. NUR EINEN!
> Wenn nun dieser Zeiger inkrementiert wird:

Das weisst du doch nicht. Der Zeiger wird meistens ein Feld sein.
von Udo K. (udok)


Lesenswert?

Nick schrieb:
> Wo ist das immer 4 Btes groß?
> Bei dir? In wie vielen Milliarden Zeilen C-Code NICHT?

Du hast keine Ahnung.
von Norbert (der_norbert)


Lesenswert?

Udo K. schrieb:
> Das weisst du doch nicht.

Das steht im Sourcecode.
1
  int k=123;
2
  fn1(&k);

Und wenn ich mit einem array arbeite, dann mache ich sichtbar:
1
#include <stdio.h>
2
int arr(int j[], unsigned long n) {
3
    return j[n];
4
}
5
int main(void) {
6
    int array_of_ints[] = {3,5,7,11};
7
    for (unsigned long idx = 0; idx < sizeof(array_of_ints)/sizeof(int); idx++) {
8
        printf("%d\n", arr(array_of_ints, idx));
9
    }
10
    return 0;
11
}
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Nick schrieb:
> dass "word" immer 16 Bit lang ist. Auf die Frage woher denn die
> Definition kommt

Tja, bei ARM ist ein Word 32bit, ein Halfword 16bit, und ein Doubleword 
64bit.
von Norbert (der_norbert)


Lesenswert?

Aber man kann sich auf Folgendes verlassen:
Die Größe eines int ist: sizeof(int)
Gilt auch für char,short,long,…,char*,short*,long*,…
Und mehr Annahmen macht man einfach nicht!
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Norbert schrieb:
> sizeof(int)

Und was genau bedeutet die Zahl die da zurückkommt? 😉
von Rick (rick)


Lesenswert?

Johann L. schrieb:
> Und wo ist da INT?
Zeile 5:     int i, j;

> Übrigens word das printf u.U. nie erreicht (Signed Overflow).
Komisch, bei mir schon.
Die resultierende Ausgabe habe ich oben mitgepostet...
von Norbert (der_norbert)


Lesenswert?

Niklas G. schrieb:
> Norbert schrieb:
>> sizeof(int)
>
> Und was genau bedeutet die Zahl die da zurückkommt? 😉

Das ist wie bei einer Schranke, man kann entweder die Höhe oder aber die 
Breite feststellen.
von Oliver S. (oliverso)


Lesenswert?

Norbert schrieb:
> Aber man kann sich auf Folgendes verlassen:
> Die Größe eines int ist: sizeof(int)
> Gilt auch für char,short,long,…,char*,short*,long*,…
> Und mehr Annahmen macht man einfach nicht!

Doch, eine: sizeof(char) ist 1. Immer.

Oliver
von Rick (rick)


Lesenswert?

Johann L. schrieb:
> Signed Overflow
Wer meldet den Fehler?
Der Compiler? Oder kommt das erst zur Laufzeit?

Hier bekomme ich auch keine Fehlermeldung:
1
$ gcc test.c -o testint                                                                                                           
2
$ ./testint                                                                                                                       
3
2147483647 -2147483648
von Nemopuk (nemopuk)


Lesenswert?

Norbert schrieb:
> Und mehr Annahmen macht man einfach nicht!

Ich meine, man kann sich bei C darauf verlassen, dass int mindestens 
16 Bit groß ist. So war das jedenfalls viele Jahre lang und es wäre 
ziemlich dumm, innerhalb der selben Sprache davon abzuweichen.
: Bearbeitet durch User
von Norbert (der_norbert)


Lesenswert?

Nemopuk schrieb:
> Ich meine, man kann sich bei C darauf verlassen, dass int mindestens
> 16 Bit groß ist.

short ist (aus dem Gedächtnis) auch als <= int und long als >= 
int definiert. Und short muss < long sein. Das ist allerdings 
alles relativ… ;-)

int könnte also 16/32Bit und vielleicht sogar bald 64Bit (bei den 
demnächst erscheinenden 128Bit Prozessoren, Speicher kostet ja gerade 
nichts) breit sein. ;-)
: Bearbeitet durch User
von Nick (b620ys)


Lesenswert?

Norbert schrieb:
> for (unsigned long idx = 0; idx < sizeof(array_of_ints)/sizeof(int);
> idx++) {

"unsigned long". <tiefes Durchschnaufen>
der Rückgabewert von sizeof ist size_t
von Harald K. (kirnbichler)


Lesenswert?

Nick schrieb:
> size_t

Es gibt anscheinend Leute, die eine tiefgreifende Aversion gegenüber 
allem haben, was mit _t endet.
von Norbert (der_norbert)


Lesenswert?

Nick schrieb:
> "unsigned long". <tiefes Durchschnaufen>
> der Rückgabewert von sizeof ist size_t

Recht hast du.
von Nick (b620ys)


Lesenswert?

Norbert schrieb:
> short ist (aus dem Gedächtnis)

Man sollte Anfängern (der TO) solches Methusalem-Wissen nicht 
beibringen.
Es existiert nur, um alte Programme noch compilierbar zu halten.

Rust hat damit konsequenterweise komplett aufgeräumt.
von Norbert (der_norbert)


Lesenswert?

Nick schrieb:
> Rust hat damit konsequenterweise komplett aufgeräumt.

Wusste gar nicht, dass wir nun bei Rust sind. ;-)
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rick schrieb:
> Johann L. schrieb:
>> Und wo ist da INT?
> Zeile 5:     int i, j;

Die steht "int" und nicht "INT"!

>> Übrigens word das printf u.U. nie erreicht (Signed Overflow).
> Komisch, bei mir schon.
> Die resultierende Ausgabe habe ich oben mitgepostet...

Dass ein Programm das macht, was du erwartest, bedeutet nicht, dass es 
korrekt ist :-)

Die Logik ist:

> Programm macht nicht was du erwartest => Programm ist inkorrekt

und

> Programm ist korrekt => Programm macht was du erwartest

Was NICHT gelten MUSS:

> Programm ist inkorrekt => Programm macht nicht was du erwartest

sowie

Programm macht was du erwartest => Programm ist korrekt.

> Komisch, bei mir schon.

Weil Undefined Behaviour kein definiertes Verhalten erfordert
- Programm kann das machen was du erwartest (was immer das ist)
- Programm kann nicht-funktional sein.
- Compiler kann eine Diagnostic ausgeben
- Compiler kann terminieren
- Programm kann sich aufhängen / abstürzen.

Letzteres passiert zu Beispiel mit GCC 13. Und mit Sanitizer:

$ gcc x.c -Os -o x.x -fsanitize=undefined && ./x.x
x.c:11:10: runtime error: signed integer overflow: 2147483647 + 1 cannot 
be represented in type 'int'

Was geht ist -fwrapv, also modular wrap-around:

$ gcc x.c -Os -o x.x -fwrapv && ./x.x
2147483647 -2147483648
von Nick (b620ys)


Lesenswert?

Norbert schrieb:
> Wusste gar nicht, dass wir nun bei Rust sind. ;-)

Nein, sind wir nicht. Da Rust schon was mit C gemeinsam hat und 
gleichzeitig völlig anders ist ... An der Speicherverwaltung wird man 
sich in Rust (aber auch weitaus unbewusster und einfacher in C) zuerst 
die Zähne ausbeissen.

Damit hat Rust aufgeräumt, weil es in C saugefährlich ist (siehe oben) 
aber gleichzeitig schon auch recht praktisch ist.
Der typgrößenwirrwar von C lässt sich leider nur durch komplettes 
ignorieren der alten Herangehensweise beheben. Und ein gutes Beispiel 
dafür wie es richtig ist, ist halt Rust. Oder/und exklusiv <stdint.h> zu 
verwenden.

Es hilft schon etwas, andere Sprachkonzepte anzuschauen. Da gibt es gute 
Lösungen an denen man sich orientieren kann.
von Norbert (der_norbert)


Lesenswert?

Nick schrieb:
> Es hilft schon etwas, andere Sprachkonzepte anzuschauen. Da gibt es gute
> Lösungen an denen man sich orientieren kann.

Verstehe worauf du hinaus willst, aber gerade für den von dir zitierten 
Anfänger kann das aber nur noch verwirrender sein. Wenn man C dann 
einigermaßen im Griff hat und wenn sich die Notwendigkeit ergibt, dann 
schaut man sich (mit diesem Grundlagenwissen) Anderes an. Python nutzt 
zB. nur eine int Klasse, die aber praktisch beliebig groß werden darf.
1
#!python
2
#!/usr/bin/python3
3
# vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
4
from math import ceil,log10
5
for n in range(1,8):
6
    print(f'# {n}^{n}^{n}: int-Länge: 10^{ceil(log10(n**n**n))}')
7
# 1^1^1: int-Länge: 10^0
8
# 2^2^2: int-Länge: 10^2
9
# 3^3^3: int-Länge: 10^13
10
# 4^4^4: int-Länge: 10^155
11
# 5^5^5: int-Länge: 10^2185
12
# 6^6^6: int-Länge: 10^36306
13
# 7^7^7: int-Länge: 10^695975
Das ist für Anfänger in C ähnlich wenig hilfreich wie Rust.
von Nick (b620ys)


Lesenswert?

Norbert schrieb:
> Python nutzt
> zB. nur eine int Klasse, die aber praktisch beliebig groß werden darf.

Das ist halt eine andere Lösung.
C ist ein "Hochsprachenassembler", wo man oft genug Platz sparen muss 
oder auf die Hardware eingehen muss (Ports mit 8 I/O etc.).
Wenn man C so lernen will, dass int immer richtig ist, dann entdeckt man 
irgendwann, dass man long braucht. Also bin ich der Meinung, dass man es 
von Anfang an richtig lernen soll. Dass es streng definierte Typen gibt 
und man damit ganz gut zurecht kommt.

C ist auf µC sehr gut aufgehoben. Für dem Desktop gibt es besser 
geeignete Sprachen.

Wenn einem das nicht gefällt, dann soll er halt Python hernehmen. Oder 
Java, oder Rust, oder C++, oder Swing, oder C#. Das hat alles seine Vor- 
und Nachteile. Es ist aber nicht hilfreich, die 
Sprachkonzepte/Paradigmen zu ignorieren oder sie nicht zu akzeptieren. 
Man will ja mit einer Sprache programmieren, nicht gegen.

Man kann ja mal versuchen C in OCamel zu übersetzen. Oder gerne auch die 
andere Richtung.
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Norbert schrieb:
> Python nutzt zB. nur eine int Klasse, die aber praktisch
> beliebig groß werden darf.

In C/C++ heißt es eben nicht "int" sondern "_BitInt".
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Frank D. schrieb:

> Das sind aber Anfängerprobleme

Willst du damit ausdrücken, der ganze C-Code, in dem dauernd 
Sicherheitslücken aufpoppen, sei ausschließlich von Anfängern 
geschrieben?

Nein, das ist natürlich nicht so.
von Harald K. (kirnbichler)


Lesenswert?

Ob S. schrieb:
> Nein, das ist natürlich nicht so.

Es gibt auch Leute, die sehr lange Dinge machen, die sie nicht richtig 
können.

Klar, denen kann man dann mit betreuten Programmiersprachen für 
"inklusives Programmieren" entgegenkommen, aber vielleicht wäre 
Rosenzüchten doch besser?
von Walter S. (avatar)


Lesenswert?

Niklas G. schrieb:
> wenn LTO aktiviert ist

danke, LTO kannte ich nicht, bin halt schon ein paar Jahrzehnte raus aus 
dem Geschäft
von Norbert (der_norbert)


Lesenswert?

Johann L. schrieb:
> In C/C++ heißt es eben nicht "int" sondern "_BitInt".

Na ja, aber man muss sich vorher festlegen und nach dem Kompilieren 
bleibt es statisch (wenn ich das richtig sehe).
Das ist etwas völlig anderes als sich selbst dynamisch nach Bedarf 
anpassende Integer (wachsend und schrumpfend).

Des weiteren ist es auch noch arg limitiert.
Um mal mein Beispiel in C zu zeigen, für 7^7^7 braucht es 2311998 Bits
1
// log(2;7^7^7) = 2311998
2
//
3
_BitInt(2311998) xxx;
1
$ gcc -Wall -Wextra -pedantic -std=c2x -no-pie -Os -o x x.c -lpthread
2
x.c:8:1: error: ‘_BitInt’ argument ‘2311998’ is larger than ‘BITINT_MAXWIDTH’ ‘65535’
3
    8 | _BitInt(2311998) xxx;
4
      | ^~~~~~~

Ad1. clang könnte es wohl, aber nur eine Zeile weiter.
Es würde dann eben bei 8^8^8 sterben.
: Bearbeitet durch User
von Nick (b620ys)


Lesenswert?

Norbert schrieb:
> Das ist etwas völlig anderes als sich selbst dynamisch nach Bedarf
> anpassende Integer (wachsend und schrumpfend).

Ich nehme einfach mal an, dass es sowas (inzwischen) auch in C++ gibt.

In Rust (sorry) gibt es das auch:
1
use num_bigint::BigUint;
Das ist die dynamische Version. Gibt auch statische Versionen.

Man kann sich solche Sachen doch selbst bauen. Auch in C. Ich brauchte 
mal dynamische Arrays. Dann schreib ich mir die halt, das dauert keinen 
Tag und man kann die ab dann immer wieder verwenden.

"Das gibts nicht" ist eine etwas einfältige Einstellung.
von Norbert (der_norbert)


Lesenswert?

Nick schrieb:
> Man kann sich solche Sachen doch selbst bauen.

Bauen kann man sich alles Mögliche. Da braucht man noch nicht einmal 
eine Programmiersprache, das geht auch in BASIC.

Hier geht es aber darum was eine Sprache (in diesem Fall C) zur 
Verfügung stellt, nicht was man hinterher nach- und dazubasteln kann.
Übrigens geht es auch nicht um C++.
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Harald K. schrieb:

> Es gibt auch Leute, die sehr lange Dinge machen, die sie nicht richtig
> können.

Oder halt auch Leute, die einfach nur Menschen sind und dementsprechend 
auch Fehler machen. Möchtegern-Göttern wie dir passiert so etwas 
natürlich niemals.

Das haben allerdings wohl auch all die anderen erfahrenen 
C-Programmierer gedacht, die die Fehler produziert haben: Ich kann das, 
ich mache keine Fehler.

> Klar, denen kann man dann mit betreuten Programmiersprachen für
> "inklusives Programmieren" entgegenkommen

Natürlich ist das der sinnvollste Ansatz! Ein Hochsprache, in der 
Menschen programmieren sollen, hat es den Menschen so einfach wie 
möglich zu machen, keine Fehler zu produzieren, sonst taugt sie nix.

Wenn es z.B. sowas wie UB gibt, dann hat der Compiler die verdammte 
Pflicht, zu warnen und darf nicht einfach stillschweigend Code 
entfernen, weil ihm der überflüssig vorkommt. Er darf und sollte(!) 
einfach sagen, dass er ihm überflüssig vorkommt.

Alles andere ist menschenuntauglicher Bullshit.
von Nick (b620ys)


Lesenswert?

Norbert schrieb:
> Da braucht man noch nicht einmal
> eine Programmiersprache, das geht auch in BASIC.

**Schenkelklopfer**
von Harald K. (kirnbichler)


Lesenswert?

Ob S. schrieb:
> Möchtegern-Göttern wie dir passiert so etwas
> natürlich niemals.

Och, den Möchtegern-Gott sehe ich doch eher bei Dir, lieber "C-Hater".
von Vanye R. (vanye_rijan)


Lesenswert?

Hier mal etwas aktuelles passendes Schulfernsehen dazu:

https://www.youtube.com/watch?v=ZcCo_Iywilk

Also entweder ihr koennt C oder ihr bereitet auch auf die 
Arbeitslosigkeit vor.

Vanye
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Vanye R. schrieb:
> Also entweder ihr koennt C oder ihr bereitet auch auf die
> Arbeitslosigkeit vor.

Claude kann kein C?

Wir lassen uns jetzt von KI-generierten Videos erklären warum C die 
einzige Sprache mit Jobsicherheit ist, was ja eigentlich nur sein könnte 
wenn es nicht KI-generierbar wäre?
: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nick schrieb:
> Man kann sich solche Sachen doch selbst bauen. Auch in C.

Gibt's doch alles, als FOSS:

Ganze und Rationale Zahlen: GMP https://gmplib.org

Reelle Zahlen (Floating): MPFR https://www.mpfr.org

Complexe Zahlen (Floating): MPC https://www.multiprecision.org

GMP has a rich set of functions, and the functions have a regular
interface. The basic interface is for C, but wrappers exist for
other languages, including Ada, C++, C#, Julia, .NET, OCaml, Perl,
PHP, Python, R, Ruby, and Rust.
von Nick (b620ys)


Lesenswert?

Johann L. schrieb:
> Gibt's doch alles, als FOSS:

Wozu dann das Gejammere. :-)
Nein, kannte ich nicht. Danke für den Hinweis.

Hätte mir aber auch nichts bei den dynamischen Arrays geholfen.
+ "Not invented here"-Syndrom.
Aber falls ich mal riesen Zahlen brauch, hoffe ich mich daran zu 
erinnern.
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nick schrieb:
> Ich warte noch darauf, dass Rust endlich mal auf µC
> implementiert wird.

Clang/LLVM unterstützt Rust und AVR.

Und im GCC ist Rust in der Mache:
1
$ ../../source/gcc-master/configure --target=avr --enable-languages=c,c++,rust ...
1
$ avr-gcc -frust-incomplete-and-experimental-compiler-do-not-use x.rs -S -Os -mmcu=atmega8 && cat x.rs && cat x.s
2
3
#![feature(no_core)]
4
#![no_std]
5
#![no_core]
6
#[allow(dead_code)]
7
pub fn mymul (x: i16, y: i16) -> i16
8
{
9
   x * y
10
}
11
12
_ZN1x5mymul17h2076d231e17342eaE:
13
  movw r18,r24
14
  movw r26,r22
15
  rcall __mulhisi3
16
  movw r20,r22
17
  movw r22,r24
18
  mov r24,r21
19
  lsl r24
20
  sbc r24,r24
21
  mov r25,r24
22
  cp r24,r22
23
  cpc r25,r23
24
  breq .L1
25
  rcall abort
26
.L1:
27
  movw r24,r20
28
  ret
29
.ident  "GCC: (GNU) 17.0.0 20260626 (experimental)"

Die einzige Frage ist wieviele Leute es gibt, die sich mit Rust 
auskennen UND mit AVR auskennen UND mit Compiler-Interna auskennen UND 
die nötigen Resourcen (Lust, Zeit, ...) mitbringen, um da was zu 
bewegen.

Zumindest bei G++ ist diese Schnittmenge über die letzten 25 Jahren 
effektiv leer...
von K. L. (trollen) Benutzerseite


Lesenswert?

Johann L. schrieb:
> avr-gcc -frust

Hihihihi
Ob die AVR-GCC-Entwickler Deutsch verstehen?
von Oliver S. (oliverso)


Lesenswert?

Johann L. schrieb:
> Clang/LLVM unterstützt Rust und AVR.

Die AVR-Unterstzung in C/C++ war doch bisher eher theoretisch, aber kaum 
praktisch nutzbar. Hat sich das inzwischen geändert?

Oliver
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Die AVR-Unterstzung in C/C++ war doch bisher eher theoretisch

Die C Unterstützung für AVR ist theoretisch? Vielleicht hast ja die 
letzten 25 Jahre verpennt :-)

Zu C++ schrub ich:

Johann L. schrieb:
> Die einzige Frage ist wieviele Leute es gibt, die sich mit Rust
> auskennen UND mit AVR auskennen UND mit Compiler-Interna auskennen UND
> die nötigen Resourcen (Lust, Zeit, ...) mitbringen, um da was zu
> bewegen.
>
> Zumindest bei G++ ist diese Schnittmenge über die letzten 25 Jahren
> effektiv leer...

Zu Clang/LLVM weiß ich nix, da hakelt es Teilweise schon mit C weil es 
keine dedizierte Libc gibt.  Und Clang ist an vielen Stellen 
inkompatibel mit GCC, d.h. Piggypack auf AVR-LibC funktioniert nicht 
wirklich gut.
: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Johann L. schrieb:
> Die C Unterstützung für AVR ist theoretisch? Vielleicht hast ja die
> letzten 25 Jahre verpennt :-)
> …
> Zu Clang/LLVM weiß ich nix, da hakelt es Teilweise schon mit C weil es
> keine dedizierte Libc gibt.

Ja, was denn jetzt? Kann man clang ernsthaft für den AVR (C/C++/Rust, 
was auch immer) nutzen, oder nicht?

Oliver
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Welchen Teil von "Zu Clang/LLVM weiß ich nix" soll ich detailiert 
erklären?

Und ja, es gibt andere C-Compiler als Clang.
von Daniel A. (daniel-a)


Lesenswert?

Rick schrieb:
1
#include <stdio.h>      // printf
2
3
void main( void)
4
{
5
    int i, j;
6
7
    i = 0;
8
    j = 1;
9
    while( j > i)
10
    {
11
        i++;
12
        j++;
13
    }
14
    printf( "%d %d\n", i, j);
15
}

Der Code ist UB. Was beim Overflow eines signed int passiert, ist 
nicht definiert. Einige Compiler machen daraus deshalb eine 
Endlosschleife: https://godbolt.org/z/qnc48jYM8
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Daniel A. schrieb:
> Der Code ist UB. Was beim Overflow eines signed int passiert,

Ja, siehe

Beitrag "Re: Anfängerproblem mit C"
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.