Gestern habe ich stundenlang nach einem Fehler gesucht, der sich als sehr raffiniert erwies. Ein Programm von mir zur Darstellung und Bearbeitung von Daten zeigte bei einer bestimmten Konfigurationsdatei plötzlich nur noch Müll, obwohl es sonst immer wie erwartet funktionierte. Eine ältere Version des Programms arbeitete auch damit korrekt. Um dem auf die Spur zu kommen, habe ich diese Datei immer wieder verkürzt und nochmal getestet. Mit 10 Zeilen war es noch Müll, mit 5 Zeilen war wieder alles in Ordnung. Schließlich stellte sich heraus, dass es zwei Zeilen waren, die das Chaos verursachten. Ohne diese beiden Zeilen funktionierte auch der Rest von 160 Zeilen. Verwirrend war, dass die beiden destruktiven Zeilen syntaktisch gleich aufgebaut waren wie die korrekten. Also musste es am Inhalt liegen. Es zeigte sich, dass die Zahlen 08 und 09 die Übeltäter waren, verkürzt auf 8 und 9 ging es dann wieder. Also nochmal in die Source geguckt, wo die Zahlen interpretiert wurden. Die Ursache liegt in der Libfunktion strtol. Mit 0 als dritten Parameter liest er auch Hexzahlen, wenn sie mit 0x anfangen. Schön praktisch, dachte ich wohl. Dass aber eine Zahl, die mit 0 anfängt, nicht dezimal sondern oktal gelesen wird, wird bei den Funktionsbeschreibungen selten erwähnt, wodurch es zu solch heimtückischen Fehlern kommt. Man kann also nur davor warnen, strtol() mit 0 als drittem Parameter zu verwenden.
Jobst Q. schrieb: > Dass aber eine Zahl, die mit 0 anfängt, nicht dezimal sondern oktal > gelesen wird, wird bei den Funktionsbeschreibungen selten erwähnt Es wird da nicht „selten“, sondern genau einmal erwähnt, unübersehbar an der dazu passenden Stelle. Mehr braucht’s nicht. https://man7.org/linux/man-pages/man3/strtol.3.html https://en.cppreference.com/w/c/string/byte/strtol Oliver
Jobst Q. schrieb: > Man kann also nur davor warnen, strtol() mit 0 als drittem Parameter zu > verwenden. Oder man liest die Doku dieser Funktion, und stellt fest, dass sie sich genau verhält wie beschrieben... Das Verhalten ist so implementiert, weil in C eine Integer-Zahl mit führender Null als Oktalzahl interpretiert wird. Du müsstest also bei nicht weiter validiertem User-Input noch eine entsprechende "Bereinigung" vornehmen.
Jobst Q. schrieb: > Man kann also nur davor warnen, strtol() mit 0 als drittem Parameter zu > verwenden. Danke für den unterhaltsamen und lehrreichen Bericht. Bitte die Leute ignorieren die alle Dokus auswendig kennen, niemals etwas übersehen und alles besser wissen.
> Bitte die Leute ignorieren die alle Dokus auswendig kennen, niemals > etwas übersehen und alles besser wissen. Hat keiner behauptet, im Gegenteil. Meinen Beitrag hätte ich auch als "RTFM!" abkürzen können, im konstruktiv gemeinten Sinne. Wenn ich so eine Funktion benutze - insbesondere eine Implementation für eine kleine 8-bit µC-Architektur - dann schaue ich immer in die Doku. Gerade weil ich nicht alles auswendig weiß, und weil es subtile Unterschiede und Einschränkungen geben kann. Die kann ich entweder selbst empirisch herausfinden, oder ich werfe vorab einen Blick in die Doku. Letzteres lernt man durch Erfahrungen, die man mit ersterem gemacht hat. Solche Parameter wie "0" für die Basis sind offensichtlich ein Sonderfall, die sich nicht aus dem Funktionsnamen ergeben! Es würde mich als Programmierer interessieren, wie sich die Funktion verhält, wenn unzulässige Zeichen in dem String vorhanden sind, etc. Diese Dinge nachzuschauen, ist nun wirklich kein Zeichen von "alles besser wissen".
Jobst Q. schrieb: > Dass aber eine Zahl, die mit 0 anfängt, nicht dezimal sondern oktal > gelesen wird, wird bei den Funktionsbeschreibungen selten erwähnt, > wodurch es zu solch heimtückischen Fehlern kommt. Ich habe auf die Schnelle (Auswertung der ersten 20 Google-Treffer von "strtol") keine einzige Funktionsbeschreibung gefunden, die den speziellen Wert 0 für das dritte Argument zwar beschreibt, aber die Bedeutung der führenden '0' des Eingabestrings als Präfix für eine Oktalzahl verschweigt. Deswegen würde ich das "selten" durch "fast immer" ersetzen. Thomas schrieb: > Bitte die Leute ignorieren die alle Dokus auswendig kennen, niemals > etwas übersehen und alles besser wissen. Wer die Doku nicht oder nicht vollständig gelesen hat, wird gar nicht erst auf die Idee kommen, als drittes Argument eine 0 zu übergeben.
Der Vollständigkeit halber noch die Stelle im C-Standard (C99 in diesem Falle, aber bis auf sich ändernde Kapitelnummerierungen steht das auch heute noch so drin): "If the value of base is zero, the expected form of the subject sequence is that of an integer constant as described in 6.4.4.1, optionally preceded by a plus or minus sign, but not including an integer suffix." 6.4.4.1 dokumentiert die Syntax der Integer-Konstanten, wie sie vom Compiler verarbeitet werden sollen.
Jochen schrieb: > Das Verhalten ist so implementiert, weil in C eine Integer-Zahl mit > führender Null als Oktalzahl interpretiert wird. So ist das eben, eine Fehlkonstruktion zieht weitere nach sich. Eine gültige Ziffer als Präfix zu verwenden ist schon ziemlich unintelligent. > Du müsstest also bei > nicht weiter validiertem User-Input noch eine entsprechende > "Bereinigung" vornehmen. Einfacher geht es, das Einlesen auf Dezimalzahlen zu beschränken. Für den Fall, viele Formate einlesen zu können, habe ich jetzt eine Rahmenfunktion geschrieben:
1 | /*-----------------------------------*/
|
2 | long int strtolx (const char* s, char** endptr){ |
3 | |
4 | int b =10; |
5 | char c; |
6 | |
7 | if(endptr != NULL)*endptr=s; |
8 | |
9 | if(*s=='0'){ |
10 | c=*(s+1)|32; |
11 | if (c =='x')b=16; |
12 | else if (c =='o'){b=8;s+=2;} |
13 | else if (c =='b'){b=2;s+=2;} |
14 | }
|
15 | |
16 | else if (*s=='_'){ |
17 | b=strtol(++s,&s,10); |
18 | if((*s != '_') || b<2 || b>36)return 0; |
19 | s++; |
20 | }
|
21 | |
22 | return strtol(s,endptr,b); |
23 | }
|
Damit kann man nicht nur Hex- (0x),Oktal- (0o)und Binärzahlen(0b) einlesen, sondern Zahlen zu beliebiger Basis in der Form: _Basis_Zahl.
:
Bearbeitet durch User
Yalu X. schrieb: > Wer die Doku nicht oder nicht vollständig gelesen hat, wird gar nicht > erst auf die Idee kommen, als drittes Argument eine 0 zu übergeben. Eben! Bei vielen Funktionen der Standard-Bibliotheken kann man sich die Verwendung anhand des Funktionsnamens und der Parameterliste (Name wegdenken!) schon intuitiv herleiten. Das ist übrigens ein sehr gut geeignetes Kriterium für die Qualität einer API! Gutes Beispiel: int strncmp(const char *, const char *, size_t) Da brauche ich keine benannten Parameter, um zu erkennen, was was ist. Schlechtes Beispiel: long int strtol(const char *, char **, int) Wofür int steht, ist nicht direkt erkennbar, wenn man strtol noch nie benutzt hat. Deshalb -> Doku...
Wenn ich so Sprüche wie
> Man kann also nur davor warnen,
lese habe ich eigentlich schon die Nase voll. Statt die Doku zu lesen
Schwurblerniveau.
Ich habe mich schon so daran gewöhnt, das Zahlen mit einer 0 davor immer octal sind, dass es mich mehr verwirren würde, wenn das ein Programm mal anders macht. Warum sollte man aber auch unnötige 0en vor dezimale Zahlen schreiben wollen? Da muss man nur suchen, wo die Zahl endlich anfängt. Besser einfach ein paar Abstände davor, wenn man es rechts bündig eingerückt haben will.
DPA schrieb: > Warum sollte man aber auch unnötige 0en vor dezimale > Zahlen schreiben wollen? Je nun, darauf hast du bei Daten, die von außen kommen, keinen Einfluß. Oliver
DPA schrieb: > Warum sollte man aber auch unnötige 0en vor dezimale > Zahlen schreiben wollen? Das ist in Zeit-Daten absolut üblich, und in Kernel-Logfiles sieht man schonmal sowas wie das hier: pcpu-alloc: [0] 00 01 02 03 04 05 06 07 [0] 08 09 10 11 12 13 14 15 pci 0000:08:00.6:
Jobst Q. schrieb: > Einfacher geht es, das Einlesen auf Dezimalzahlen zu beschränken. Für > den Fall, viele Formate einlesen zu können, habe ich jetzt eine > Rahmenfunktion geschrieben: > [...Bugs und implementation defined behavior...] > Damit kann man nicht nur Hex- (0x),Oktal- (0o)und Binärzahlen(0b) > einlesen, sondern Zahlen zu beliebiger Basis in der Form: _Basis_Zahl. Über strtol beschweren aber dann so einen Mist schreiben.
Nop schrieb: > DPA schrieb: >> Warum sollte man aber auch unnötige 0en vor dezimale >> Zahlen schreiben wollen? > > Das ist in Zeit-Daten absolut üblich Die einzelnen Zahlen in Zeitangaben werden aber praktisch immer dezimal geschrieben. Deswegen wird man dafür das dritte Argument von strtol einfach auf 10 setzen, und die "Oktalfalle" ist beseitigt.
Was mich in der Hinsicht eigentlich immer am ehesten geärgert hat: wenn man irgendeinen generischen String braucht, kann man immer "foo" nehmen. Für eine generische Zahl kann man jedoch nicht "0815" benutzen. :)
Jörg W. schrieb: > Was mich in der Hinsicht eigentlich immer am ehesten geärgert hat: wenn > man irgendeinen generischen String braucht, kann man immer "foo" nehmen. > Für eine generische Zahl kann man jedoch nicht "0815" benutzen. :) Deswegen hat sich das Internet auf 42 geeinigt :-) (Stell dir mal vor du würdest antworten "der Fehler ist in Zeile 0815")
Jobst Q. schrieb: > Für > den Fall, viele Formate einlesen zu können, habe ich jetzt eine > Rahmenfunktion geschrieben: Bei der du statt der in C üblichen Schreibweise zwei andere umsetzt, die beide auch sonst nirgends gebräuchlich sind. Gerade auf sowas würde ich verzichten, wenn ich nicht einen sehr guten Grund hätte, von gängigen Schreibweisen abzusehen. > /*-----------------------------------*/ > long int strtolx (const char* s, char** endptr){ Der Name ist übrigens ungültig. Alles, was mit str gefolgt von einem Kleinbuchstaben beginnt, ist für den Compiler bwz. die Standardbibliothek reserviert. Jörg W. schrieb: > Was mich in der Hinsicht eigentlich immer am ehesten geärgert hat: wenn > man irgendeinen generischen String braucht, kann man immer "foo" nehmen. > Für eine generische Zahl kann man jedoch nicht "0815" benutzen. :) Da nimmt man ja auch 42. Wenn's denn vierstellig sein muss, hat damals mein Professor immer 4711 verwendet. Übrigens wäre 0815 auch streng genommen nicht richtig. Das MG heißt ja eigentlich 08/15.
Ich bin schon Software begegnet, die IP Adressen mit strtol(,0) konvertiert. Wer dann seine Adresse als 192.168.178.010 eingibt...
Rolf M. schrieb: > Das MG heißt ja eigentlich 08/15. In hiesiger Branche also nicht von 08/14 unterscheidbar, weil beides 0.
C hält sich streng an einmal festgelegte Regeln, das ist doch schön. Hast Du schon mal mit Excel gearbeitet? Das hat einen eingebauten Zufallsgenerator, wie es importierte Zahlenreihen umzuwandeln gedenkt. Mal werden es dann Währungen oder Zeiten oder Datumsangaben oder sonstwas. Wenn man da nicht aufpaßt, wie ein Lux, sind die mühsam erstellten Meßreihen für die Katz.
Jobst Q. schrieb: > Damit kann man nicht nur Hex- (0x),Oktal- (0o)und Binärzahlen(0b) > einlesen, sondern Zahlen zu beliebiger Basis in der Form: _Basis_Zahl. Und? Wozu sollte das gut sein? Nur um der Welt zu zeigen, wie gut du programmieren kannst? Normalerweise weiß man als Programmierer, was für numerische Eingaben das Programm an welcher Stelle erwartet. Folglich sollte man unbenutzte Zahlenformate erst gar nicht implementieren, um vor Fehlern bei der Benutzung eher geschützt zu sein und den Benutzer besser auf ein falsch getipptes Zeichen hinweisen zu können. W.S.
Es sei noch erwähnt, dass sich der Formatspecifier %i bei scanf genauso verhält.
(prx) A. K. schrieb: > In hiesiger Branche also nicht von 08/14 unterscheidbar, weil beides 0. 08 ist schon keine gültige Zahl.
Peter D. schrieb: > C hält sich streng an einmal festgelegte Regeln, das ist doch schön. > > Hast Du schon mal mit Excel gearbeitet? > Das hat einen eingebauten Zufallsgenerator, wie es importierte > Zahlenreihen umzuwandeln gedenkt. Mal werden es dann Währungen oder > Zeiten oder Datumsangaben oder sonstwas. > Wenn man da nicht aufpaßt, wie ein Lux, sind die mühsam erstellten > Meßreihen für die Katz. Ich weiß nicht wie es bei Excel ist, aber ein eher unbekannter online Konkurrent wandelt die Eingabe 2015-06-05 automatisch in den Wert 2015-05-06 ;-)
(prx) A. K. schrieb: > Ich bin schon Software begegnet, die IP Adressen mit strtol(,0) > konvertiert. Wer dann seine Adresse als 192.168.178.010 eingibt... Das hat nicht unbedingt mit strtol zu tun. Diese Interpretation ist bei den Berkley-Sockets so vorgesehen und z.B. auch in Linux in manchen Tools so vorhanden. Aus der man-Page der Funktion inet_aton() (und inet_addr): "In all of the above forms, components of the dotted address can be specified in decimal, octal (with a leading 0), or hexadecimal, with a leading 0X). Addresses in any of these forms are collectively termed IPV4 numbers-and-dots notation. The form that uses exactly four decimal numbers is referred to as IPv4 dotted-decimal notation (or sometimes: IPv4 dotted-quad notation)." Daher gibt es durchaus einige Kommandozeilen-Programme, die das so interpretieren. Die POSIX-Version der Funktion (die dann inet_pton() heißt) definiert dagegen nur die dezimale Notation. Aus dessen man-Page: AF_INET src points to a character string containing an IPv4 network address in dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number of up to three digits in the range 0 to 255. Interessant ist die Dokumentation von inet_addr unter Windows. Da heißt es: "The inet_addr function converts a string containing an IPv4 dotted-decimal address into a proper address for the IN_ADDR structure." Weiter unten heißt es dann aber dem widersprechend, dass dort auch Oktal und Hexadezimal gehen. https://docs.microsoft.com/en-us/windows/win32/api/wsipv6ok/nf-wsipv6ok-inet_addr
:
Bearbeitet durch User
Bei IPs hat irgendwer auch mal noch Kurzformen eingeführt. 127.1 entspricht 127.0.0.1 ... Und dann gehen meistens noch Sachen wie 0x7F000001 oder 0x7f.1, was dann zu 127.0.0.1 wird!!!
Peter D. schrieb: > C hält sich streng an einmal festgelegte Regeln, das ist doch schön. Das wäre schön, wenn diese Regeln in der heutigen Zeit noch sinnvoll wären. Sie stammen aber leider aus einer Zeit, die ca. ein halbes Jahrhundert her ist. Speziell das Oktalsystem ist heute vollkommen huppse. Nur genauso historische APIs und OSs wie etwa POSIX und Linux benutzen so einen Quatsch noch. Die heilige Abwärtskompatibilität schleppt hier völlig überflüssige Scheisse über Jahrzehnte mit. > Hast Du schon mal mit Excel gearbeitet? > Das hat einen eingebauten Zufallsgenerator, wie es importierte > Zahlenreihen umzuwandeln gedenkt. Quatsch. Bei Excel werden genauso Regeln angewandt wie bei C. Nur halt andere. Wenn man sie lernt, kann man damit genauso souverän umgehen, wie mit den (mindestens genauso) schwachsinnigen Regeln von C.
c-hater schrieb: > Bei Excel werden genauso Regeln angewandt wie bei C. Nur halt > andere. Wenn man sie lernt, kann man damit genauso souverän umgehen, wie > mit den (mindestens genauso) schwachsinnigen Regeln von C. Wo genau sind die Regeln dokumentiert, wann und wie ein Datum in ein anderes konvertiert werden? Dir ist klar, dass C nicht alleine ist mit diesen Regeln? Soweit ich weiß nutzen Java, C#, und Go die gleiche Schreibweise für oktale Literale.
Mombert H. schrieb: > Soweit ich weiß nutzen Java, C#, und Go die gleiche Schreibweise für > oktale Literale. Bei Java und C# wundert es nicht, denn sie haben zu einem Teil die Syntax (vor allem von C++) geerbt. Bei Go schon eher. Gerade nachgesehen, eine formale Syntaxbeschreibung für Rust gibt es leider nicht, aber irgendwo im Rust-Buch erwähnen sie dann, dass Oktalzahlen mit `0o' eingeleitet werden. Durchaus eine vernünftige Entscheidung. Aber die Entscheidung, dass man Oktalzahlen gar nicht mehr brauchen kann, haben sie sich auch nicht getraut. :)
Daniel A. schrieb: > Und dann gehen meistens noch Sachen wie 0x7F000001 oder 0x7f.1, was dann > zu 127.0.0.1 wird!!! Das musst du garnicht hexadezimal machen oder mit Punkten trennen, das funktioniert auch als einfache Dezimalzahl. Die meisten Browser (oder alle?) wandeln folgende URL: http://3232235777 automatisch nach http://192.168.1.1 Damit sieht man auch, wie man aufpassen muss, wenn man bestimmte IP-Adressen sperren will, ein einfacher String Match mit "192.168.*" reicht dazu nicht. Michael
Es wäre praktisch, wenn man Sachen wie 16xABCDEF 8x0123457 64xdEf= machen könnte. also basis x zahl.
Daniel A. schrieb: > Es wäre praktisch, wenn man Sachen wie 16xABCDEF 8x0123457 64xdEf= > machen könnte. also basis x zahl. Ada: 16#ABCDEF#.
Jörg W. schrieb: > Gerade > nachgesehen, eine formale Syntaxbeschreibung für Rust gibt es leider > nicht, aber irgendwo im Rust-Buch erwähnen sie dann, dass Oktalzahlen > mit `0o' eingeleitet werden. Die Syntaxbeschreibung gibt es in der Doku. Zu den Integer-Literals: https://doc.rust-lang.org/reference/tokens.html#integer-literals
:
Bearbeitet durch User
Rolf M. schrieb: > Zumindest die lexikalischen Regeln sind beschrieben. Danke, zumindest unter "Dokumentation" habe ich das auf rust-lang.org so schnell nicht gefunden. Ja, irgendsowas hatte ich da eigentlich erwartet. Ich weiß, auch C hat mit einem Paper und dann später einem Buch angefangen, aber die hatten wenigstens im Anhang auch immer die formale Syntaxbeschreibung mit drin. Das habe ich als Anhang im Rust-Buch vermisst.
c-hater schrieb: > Bei Excel werden genauso Regeln angewandt wie bei C. Nur halt > andere. Das Problem ist aber, daß Excel Zahlenreihen nicht gleich behandelt. Wenn ich eine Reihe importiere, werden die meisten Werte richtig übernommen, aber einige werden in Unsinn konvertiert. Man kann also nicht einfach Datensätze mit Trennzeichen einlesen. Man muß jede Spalte für sich markieren, das richtige Format aufzwingen und dann jede Spalte einzeln importieren. Ein weiteres Problem sind Datensätze mit Dezimalpunkt. Die muß man mit einem extra Texteditor in Dezimalkomma konvertieren.
Peter D. schrieb: > Die muß man mit einem extra Texteditor in > Dezimalkomma konvertieren. Auch das geht mit Excel. Oliver
Oliver S. schrieb: > Peter D. schrieb: >> Die muß man mit einem extra Texteditor in Dezimalkomma konvertieren. > Auch das geht mit Excel. Genau. Das hängt aber auch von der Dateiendung der Datei (.csv oder .txt) und den Locale-Einstellungen des Users an. Man kann natürlich auch die Einstellungen beim Import selbst noch verändern und die korrekte Codepage einstellen... Ich bin so froh, dass das .csv Format immer mehr durch .json ersetzt wird, auch wenn da auch nicht alles perfekt ist. Michael
:
Bearbeitet durch User
DPA schrieb: > Warum sollte man aber auch unnötige 0en vor dezimale > Zahlen schreiben wollen? Ähnlich beschränkt haben wohl auch diejenigen gedacht, die den Bockmist verzapft haben, dass eine Zahl mit 0 am Anfang nicht dezimal,sondern oktal zu interpretieren ist. Und damit auf eine klare Trennung von Syntax und Inhalt verzichtet haben. 0 ist eine gültige Dezimalziffer und damit als alleiniges Prefix völlig ungeeignet. Es gibt sehr wohl gute Gründe für Dezimalzahlen, die mit 0 anfangen. Ein Grund ist die feste Breite einer Zahlenfolge. Damit werden selbst Namen mit Buchstaben und Ziffern richtig sortiert. ZB bei Dateinamen, die das Datum enthalten, wie foo220106. Daraus kann man an fester Stelle etwa den Monat zurücklesen. Bis zum Juli geht das auch mit Oktalzahlen, aber im August knallt es dann. Ein anderer Grund ist, dass man mehrstellige Zahlen besser suchen und ersetzen kann als einzelne Ziffern. Eine "1" findet man recht häufig, "001" ist da wesentlich zielgerichteter.
Jobst Q. schrieb: > Es gibt sehr wohl gute Gründe für Dezimalzahlen, die mit 0 anfangen. Ja, dann sagt man der auswertenden Funktion schlicht, dass es sich um eine Dezimalzahl handelt (base = 10), dann funktioniert das auch. Wurde aber alles schon geschrieben.
Peter D. schrieb: > Man kann also nicht einfach Datensätze mit Trennzeichen einlesen. Man > muß jede Spalte für sich markieren, das richtige Format aufzwingen und > dann jede Spalte einzeln importieren. Laß mal, andere Tabellenkalkulationen sind in diesem Punkt genau so zickig wie Excel. Ich hatte da ähnliche Erfahrungen wie du sammeln können. Insbesondere beim Importversuch von Daten aus Meßgeräten, was mit boshafter Hartnäckigkeit an den verschiedensten Stellen schief ging. Naja, es sind Tabellenkalkulationen eben zuvörderst dazu gedacht, daß Nichtprogrammierer, also Kaufleute usw. manuell damit umgehen. W.S.
Jörg W. schrieb: > Jobst Q. schrieb: >> Es gibt sehr wohl gute Gründe für Dezimalzahlen, die mit 0 anfangen. > > Ja, dann sagt man der auswertenden Funktion schlicht, dass es sich um > eine Dezimalzahl handelt (base = 10), dann funktioniert das auch. > > Wurde aber alles schon geschrieben. Ich habe nirgendwo geschrieben, dass es keine Lösung für das Problem gibt. Die Änderung von 0 auf 10 war Sache von Sekunden, schon vor eurer "Hilfe". Aufwendig war nur, die Ursache für das Problem zu finden. Um das anderen Programmierern zu ersparen, habe ich hier die Warnung verfasst.
Das Blöde ist ja nur, dass Excel behauptet, mit CSV-Daten umgehen zu können und sich den Suffix krallt, dann aber Mist draus macht. Über den umständlichen Weg (neues Dokument anlegen, Text aus Datei einfügen) kann man das alles parametrieren, warum dann nicht gleich, wenn man initial eine CSV-Datei damit öffnet? Aber das ist OT hier.
Rolf M. schrieb: > Jobst Q. schrieb: >> Für >> den Fall, viele Formate einlesen zu können, habe ich jetzt eine >> Rahmenfunktion geschrieben: > > Bei der du statt der in C üblichen Schreibweise zwei andere umsetzt, die > beide auch sonst nirgends gebräuchlich sind. Gerade auf sowas würde ich > verzichten, wenn ich nicht einen sehr guten Grund hätte, von gängigen > Schreibweisen abzusehen. Die in C übliche Schreibweise von Oktalzahlen ist ja gerade das Problem. Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang haben sollten. Binär-Konstanten fehlen leider in C. Wüsste aber kein Prefix, das üblicher und sinnvoller wäre als '0b'. Für Zahlen mit beliebiger Basis habe ich keine gängigen Schreibweisen gefunden. Kennst du welche, die sinnvoller sind? >> /*-----------------------------------*/ >> long int strtolx (const char* s, char** endptr){ > > Der Name ist übrigens ungültig. Alles, was mit str gefolgt von einem > Kleinbuchstaben beginnt, ist für den Compiler bwz. die > Standardbibliothek reserviert. Darüber hat sich bei mir noch kein Compiler beschwert, solange ich nicht dieselben Namen benutze. Ich könnte es natürlich auch xstrtol nennen, sehe dazu aber keinen Anlass.
Jobst Q. schrieb: > Binär-Konstanten fehlen leider in C. Werden in C23 endlich drin sein (nachdem praktisch alle anderen Sprachen sie schon hatten, inklusive C++). > Darüber hat sich bei mir noch kein Compiler beschwert, solange ich nicht > dieselben Namen benutze. Ich könnte es natürlich auch xstrtol nennen, > sehe dazu aber keinen Anlass. "Absence of evidence is no evidence of absence". Das ist eine Aussage wie: "Ich gehe immer bei Rot über die Straße, ist noch nie was passiert, ich habe keinen Anlass, daran was zu ändern." Der Compiler muss sich auch nicht drüber beschweren, er kann einfach komplett was anderes machen dann, ganz und gar ohne sich zu beschweren. Im Gegensatz zu der von dir proklamierten "Oktalzahlen-Falle" ist das nämlich wirklich eine Falle, in die man unbedarft tapsen kann.
Jobst Q. schrieb: > Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang > haben sollten. Warum sollten sie Vorrang haben? Jobst Q. schrieb: > Für Zahlen mit beliebiger Basis habe ich keine gängigen Schreibweisen > gefunden. Kennst du welche, die sinnvoller sind? Und wenn du denkst, dass dezimal Vorrang haben sollte, warum benutzt du dann überhaupt eine andere Basis in einer Konfigdatei? Jobst Q. schrieb: > Darüber hat sich bei mir noch kein Compiler beschwert, solange ich nicht > dieselben Namen benutze. Ich könnte es natürlich auch xstrtol nennen, > sehe dazu aber keinen Anlass Warum sollte man sich auch an die Regeln der Sprache halten? Und wenn der Compiler warnen würde, hättest du die Warnung vermutlich genauso ignoriert wie die anderen Warnungen, die für dein strtolx generiert werden.
Jobst Q. schrieb: > Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang > haben sollten. Das Dezimalsystem finde ich echt scheisse. Bei den üblichen Basen 2 8 16 64 256 (btw. 1 byte), etc. kann man recht einfach dazwischen konvertieren, und muss nicht die ganze zahl kennen. Ich kann einige Ziffern am Anfang, Ende, Mitte, etc. nehmen, und davon ein paar Ziffern in der anderen Basis ableiten. Aber mit base 10 geht das nicht. (Weil, es gibt keine Zahl x für die gilt x=2^a=10^b wo a,b,x Integer und x>0 sind). Bei Basis 10 muss ich ganz rechts anfangen, und jede Ziffer anschauen, um das in eine der anderen Basen konvertieren zu können. Extrem unpraktisch. Das Dezimalsystem sollte man abschaffen.
Mombert H. schrieb: > Jobst Q. schrieb: >> Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang >> haben sollten. > Warum sollten sie Vorrang haben? Weil Menschen zehn Finger haben.
c-hater schrieb: > Mombert H. schrieb: > >> Jobst Q. schrieb: >>> Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang >>> haben sollten. >> Warum sollten sie Vorrang haben? > > Weil Menschen zehn Finger haben. Und zwei Hände, Arme, Beinde, Beine, Augen, Ohren, Nieren, ...
DPA schrieb: > Extrem unpraktisch. Das Dezimalsystem sollte man abschaffen. Ist dein Vorname Sheldon? Oliver
Jobst Q. schrieb: >> Bei der du statt der in C üblichen Schreibweise zwei andere umsetzt, die >> beide auch sonst nirgends gebräuchlich sind. Gerade auf sowas würde ich >> verzichten, wenn ich nicht einen sehr guten Grund hätte, von gängigen >> Schreibweisen abzusehen. > > Die in C übliche Schreibweise von Oktalzahlen ist ja gerade das Problem. > Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang > haben sollten. Ich nehme lieber etwas etabliertes, statt was eigenes zu erfinden, das sonst keiner kennt. > Binär-Konstanten fehlen leider in C. Wüsste aber kein Prefix, das > üblicher und sinnvoller wäre als '0b'. Das ist ok. Ist ja auch (außer bisher noch in C) durchaus schon so gebräuchlich. > Für Zahlen mit beliebiger Basis habe ich keine gängigen Schreibweisen > gefunden. Kennst du welche, die sinnvoller sind? Hast du je eine andere Basis als 2, 8, 10 oder 16 gebraucht? Ich nicht. Daher sehe ich keine Notwendigkeit, bei jeder Zahleneingabe die Möglichkeit zu haben, eine eigene beliebige Basis angeben zu können.
:
Bearbeitet durch User
Rolf M. schrieb: >> Die in C übliche Schreibweise von Oktalzahlen ist ja gerade das Problem. >> Dass es zu Konflikten mit Dezimalzahlen kommt, die ja eindeutig Vorrang >> haben sollten. > > Ich nehme lieber etwas etabliertes, statt was eigenes zu erfinden, das > sonst keiner kennt. Ob jemand anderes das kennt, spielt für mich kaum eine Rolle. Die meisten meiner Programme sind Teil eines Steuerungssystems, das keine Bedienung erfordert und von mir konfiguriert und überwacht wird. Es sind Dämone und Konsolenprogramme, die in Scripten und manuell eingesetzt werden. Kriterien sind Zuverlässigkeit, Vielseitigkeit auch für zukünftige Aufgaben und dass ich damit effizient arbeiten kann. Gerade solche Erfahrungen wie jetzt mit strtol gehen in die Richtung: "Traue keiner Funktion, die du nicht selbst geschrieben hast." Wie etabliert sie auch immer sein mögen. > Hast du je eine andere Basis als 2, 8, 10 oder 16 gebraucht? Ich nicht. > Daher sehe ich keine Notwendigkeit, bei jeder Zahleneingabe die > Möglichkeit zu haben, eine eigene beliebige Basis angeben zu können. Ich werde sie auch nur selten einsetzen. Aber wenn strtol schon die Möglichkeit bietet, Zahlen mit jeder Basis von 2 bis 36 einzulesen, warum dann nicht auch ein fertiges Programm mit dieser Möglichkeit. Man weiß ja nicht, welche Aufgaben es in der Zukunft geben wird. Zahlen mit der Basis 4 oder 32 sind für Bitmuster ähnlich geeignet wie Oktalzahlen oder Hexadezimalzahlen. Die Basis 36 erlaubt es zB alle Grundbuchstaben als Ziffern einzusetzen und Worte sind nunmal leichter zu merken als Zahlen. Für die Interprozeßkommunikation zb Messagequeue braucht man jeweils einen 32-Bit Schlüssel zur Identifikation. Bisher habe ich es mit 4 Buchstaben eines Prozesses als Bytes gelöst: key_t MsgKey='w'+'a'*0x100+'t'*0x10000+'c'*0x1000000; Mit der Zahlenbasis 36 könnte man bis zu 6 Buchstaben verwenden, oder bei Programmen mit mehreren Prozessen 5 Buchstaben aus dem Programmnamen und eine Ziffer als durchlaufende Nummerierung.
:
Bearbeitet durch User
Peter D. schrieb: > C hält sich streng an einmal festgelegte Regeln, das ist doch schön. Ja schön. Einmal Bockmist festgelegt und gilt für immer und ewig. Und wird auch noch von neueren Sprachen übernommen. C wird immer pingeliger, ständig gibt es neue Regeln und Vorschriften. Aber der alte Mist bleibt.
Jobst Q. schrieb: > Die Basis 36 erlaubt es zB alle Grundbuchstaben als Ziffern Vielleicht reichen 32 Buchstaben? Wäre viel einfacher.
Josef G. schrieb: > Jobst Q. schrieb: >> Die Basis 36 erlaubt es zB alle Grundbuchstaben als Ziffern > > Vielleicht reichen 32 Buchstaben? Wäre viel einfacher. Zahlen mit Basis 36 haben 0-9 + 26 Buchstaben als gültige Ziffern. Mit der Basis 32 müsste auf w,x,y und z verzichtet werden.
Jobst Q. schrieb: > C wird immer pingeliger, ständig gibt es neue Regeln und Vorschriften. Tatsächlich? In den 33 Jahren seit seiner Standardisierung gab es genau 3 neue Versionen. Da kann man nicht gerade von "ständig" sprechen. Und mir ist auch nicht bekannt, wo da was pingeliger geworden wäre. Was du vielleicht meinst ist, dass neuere Compiler mehr Fehler im Code finden bzw. darüber stolpern. Das liegt aber daran, dass diese Compiler mehr Optimierungspotenziale ausschöpfen und den Code besser analysieren. Die allermeisten solcher Fehler sind vorher lediglich unentdeckt geblieben, waren aber eigentlich schon immer Fehler. > Aber der alte Mist bleibt. C ist sehr darauf bedacht, dass bestehender Code weitestgehend gültig bleibt. Wenn man sich mal anschaut, wie lange praktisch jedes Linux-System python2 und python3 parallel installiert haben musste, bis mal endlich alle Skripte nach python3 migriert waren, kann man schon den Vorteil in der Rückwärtskompatibilität sehen.
:
Bearbeitet durch User
Jobst Q. schrieb: > > Die in C übliche Schreibweise von Oktalzahlen ist ja gerade das Problem. Wo auch immer das herkommen mag, ändern kann man das jetzt nicht mehr. Auch wenn heute wohl die meisten C-Programmierer in Ihren Programmen nur eine einzige Oktalzahl verwenden: 0. > Binär-Konstanten fehlen leider in C. Wüsste aber kein Prefix, das > üblicher und sinnvoller wäre als '0b'. Binärkonstanten gibt es in C (ab ISO C23), und das Präfix ist 0b.
DPA schrieb: > Das Dezimalsystem sollte man abschaffen. Du solltest dich am Strang "8bit-Computing mit FPGA" beteiligen. Josef G. schrieb: > Ein kleiner Hobby-Computer mit einem Zeichensatz, der neben > Buchstaben und Sonderzeichen auch einen auf sechzehn Ziffern > erweiterten Ziffernsatz enthält ...
Jobst Q. schrieb: > Zahlen mit Basis 36 haben 0-9 + 26 Buchstaben als gültige Ziffern. Mit > der Basis 32 müsste auf w,x,y und z verzichtet werden. Oder auf i, L, o und B
Dirk B. schrieb: > Oder auf i, L, o und B Wenn es darum geht, lange Bitfolgen platzsparend zu drucken: Alle 26 Buchstaben verwenden und dazu die Ziffern 1 bis 6. So wären ungültige Zeichen leicht zu erkennen, finde ich.
Eine Basis außerhalb des Bereichs bis 36, die auch tatsächlich oft Verwendung findet, ist 64 (entsprechend Base64 genannt). Die nutzt neben allen Groß- und Kleinbuchstaben sowie den Ziffern noch das + und das /, um damit pro Stelle 6 Bit darstellen zu können.
:
Bearbeitet durch User
Philipp Klaus K. schrieb: > Jobst Q. schrieb: >> >> Die in C übliche Schreibweise von Oktalzahlen ist ja gerade das Problem. > > Wo auch immer das herkommen mag, ändern kann man das jetzt nicht mehr. Bei Python 3 hat man das Präfix auch geändert von 0 auf 0o. Warum sollte es bei C oder Java nicht möglich sein? Da gibt es ja auch immer wieder neue Normen: https://de.wikipedia.org/wiki/Varianten_der_Programmiersprache_C Es wären 2 Schritte: 1. Das Prefix 0o alternativ ermöglichen. Bei alten Konstanten mit 0 eine Warnung ausgeben,dass es bald abgeschafft wird. Libaryfunktionen wie strtol oder scanf auf 0o umstellen und mit Warnungen darauf hinweisen, dass sonst dezimal gelesen wird. 2. Konstanten mit 0 als Fehler behandeln, wenn es nicht mit einem speziellen Flag compiliert wird. > Auch wenn heute wohl die meisten C-Programmierer in Ihren Programmen nur > eine einzige Oktalzahl verwenden: 0. Das wäre ein Grund nicht auf alten Fehlern zu bestehen. > >> Binär-Konstanten fehlen leider in C. Wüsste aber kein Prefix, das >> üblicher und sinnvoller wäre als '0b'. > > Binärkonstanten gibt es in C (ab ISO C23), und das Präfix ist 0b. Leider haben wir noch nicht 23, aber es macht Hoffnung.
Wenn du so ein großes Problem mit C hast, warum benutzt du es dann? Zwingt dich jemand dazu? Wenn ja solltest du dich über diese Person beschweren und nicht über C ;-)
Mombert H. schrieb: > Wenn du so ein großes Problem mit C hast, warum benutzt du es dann? > Zwingt dich jemand dazu? Wenn ja solltest du dich über diese Person > beschweren und nicht über C ;-) Nein, ich liebe C und halte sie für eine geniale Sprache. Von der Null als Oktalprefix mal abgesehen. Die C-Standardfunktionen dagegen sind nicht immer optimal, deshalb bevorzuge ich eigene Funktionen.
Jobst Q. schrieb: > 1. Das Prefix 0o alternativ ermöglichen. Oja,
1 | int a = 0O0; |
2 | int b= 0O10; |
Einfach nur toll.
Finger weg von C ;-) schrieb: > Jobst Q. schrieb: >> 1. Das Prefix 0o alternativ ermöglichen. > > Oja, > int a = 0O0; > int b= 0O10; > > Einfach nur toll. Warum hast du O statt o genommen? Damit es schlechter lesbar ist und du dich dann darüber beschweren kannst, dass es schlecht lesbar ist?
Rolf M. schrieb: > Finger weg von C ;-) schrieb: >> Jobst Q. schrieb: >>> 1. Das Prefix 0o alternativ ermöglichen. >> >> Oja, >> int a = 0O0; >> int b= 0O10; >> >> Einfach nur toll. > > Warum hast du O statt o genommen? Damit es schlechter lesbar ist und du > dich dann darüber beschweren kannst, dass es schlecht lesbar ist? Da 0x/0X und 0b/0B erlaubt sind. sollte wohl auch 0O erlaubt sein, wenn 0o erlaubt ist. Es ist ja nicht so als wäre 0B besonders gut lesbar ...
Jobst Q. schrieb: > Bei Python 3 hat man das Präfix auch geändert von 0 auf 0o. Python 3 ist aber auch ein typisches Beispiel, wie man sich einen Versionswechsel in einer Programmiersprache nicht wünscht, und wie ihn C gewiss nicht machen würde. Wenn, dann hätte man das vielleicht 1989 schon feststellen sollen, dann könnten wir jetzt, mehr als 30 Jahre später, vielleicht die alten Oktalzahlen endgültig verbieten. Auch aktuelle Systeme haben nämlich durchaus noch welche in Headerfiles drin. Als Klassiker hätte ich hier einen Auszug aus <sys/stat.h>:
1 | #define S_ISUID 0004000 /* set user id on execution */ |
2 | #define S_ISGID 0002000 /* set group id on execution */ |
3 | #define S_ISTXT 0001000 /* sticky bit */ |
4 | |
5 | #define S_IRWXU 0000700 /* RWX mask for owner */ |
6 | #define S_IRUSR 0000400 /* R for owner */ |
7 | #define S_IWUSR 0000200 /* W for owner */ |
8 | #define S_IXUSR 0000100 /* X for owner */ |
9 | |
10 | #define S_IRWXG 0000070 /* RWX mask for group */ |
11 | #define S_IRGRP 0000040 /* R for group */ |
12 | #define S_IWGRP 0000020 /* W for group */ |
13 | #define S_IXGRP 0000010 /* X for group */ |
14 | |
15 | #define S_IRWXO 0000007 /* RWX mask for other */ |
16 | #define S_IROTH 0000004 /* R for other */ |
17 | #define S_IWOTH 0000002 /* W for other */ |
18 | #define S_IXOTH 0000001 /* X for other */ |
19 | |
20 | #define S_IFMT 0170000 /* type of file mask */ |
21 | #define S_IFIFO 0010000 /* named pipe (fifo) */ |
22 | #define S_IFCHR 0020000 /* character special */ |
23 | #define S_IFDIR 0040000 /* directory */ |
24 | #define S_IFBLK 0060000 /* block special */ |
25 | #define S_IFREG 0100000 /* regular */ |
26 | #define S_IFLNK 0120000 /* symbolic link */ |
27 | #define S_IFSOCK 0140000 /* socket */ |
28 | #define S_ISVTX 0001000 /* save swapped text even after use */ |
Jobst Q. schrieb: > es bei C oder Java nicht möglich sein? Da gibt es ja auch immer wieder > neue Normen Die Fortentwicklung des C-Standards ist extrem konservativ. Bestehender Code wird wenn möglich nicht angetastet. Auch manche Compiler beherzigen dies, weshalb GCC noch heute klassischen K&R Code mit Funktionen ohne Parameterdeklarationen aus der Zeit vor ANSI-C 1989 akzeptiert.
:
Bearbeitet durch User
Finger weg von C ;-) schrieb: > Jobst Q. schrieb: >> 1. Das Prefix 0o alternativ ermöglichen. > > Oja, > >
1 | > int a = 0O0; |
2 | > int b= 0O10; |
3 | >
|
> > Einfach nur toll. Die Ästhetik spielt dabei nicht so eine Rolle. Für einen völligen Neuanfang hätte ich 0k vorgeschlagen. Bei Hex-Zahlen wurde ja auch das x genommen und nicht das h. Aber da in Python und vielleicht in anderen Sprachen schon 0o festgelegt wurde, bin ich mehr für Einheitlichkeit. Wer Probleme mit der Unterscheidung von Ziffern und Buchstaben wie 0 und O oder 1 und l hat, sollte sich einen besseren Font für seinen Editor wählen.
Jobst Q. schrieb: > Für einen völligen Neuanfang hätte ich 0k vorgeschlagen. Bei Hex-Zahlen > wurde ja auch das x genommen und nicht das h. Warum k?
Jobst Q. schrieb: > Für einen völligen Neuanfang hätte ich 0k vorgeschlagen nah. Prefix durch Unterstrich klar trennen, wie Python und Rust es beherrschen:
1 | >>> 0o_101 |
2 | 65 |
3 | >>> 0x_101 |
4 | 257 |
5 | >>> 0b_101 |
6 | 5 |
1 | fn main() { |
2 | let _x = 0o_101; |
3 | let _x = 0x_101; |
4 | let _x = 0b_101; |
5 | } |
MaWin schrieb: > Prefix durch Unterstrich klar trennen, wie Python und Rust es > beherrschen Ist in C23 ein Apostroph (in C++ wohl auch). Unterstrich hat man nicht genommen, weil es ein legaler Bezeichner ist, der auch an einigen Stellen (vor allem im Bereich der Internationalisierung) schon üblich ist. Also
1 | #define S_IXOTH 0'000'001 /* X for other */ |
geht dann dort.
Jörg W. schrieb: > MaWin schrieb: >> Prefix durch Unterstrich klar trennen, wie Python und Rust es >> beherrschen > > Ist in C23 ein Apostroph (in C++ wohl auch). Ja, C++ hat das (und den Präfix 0b für Binary) mit C++14 eingefügt. Der Apostroph ist aber eher für die Gruppierung der Ziffern z.B. in 3er-Gruppen gedacht und darf nun gerade nicht direkt nach einem 0x oder 0b kommen. 0x'101 ist also nicht erlaubt, 0x1'01 schon. > Unterstrich hat man nicht genommen, weil es ein legaler Bezeichner ist, > der auch an einigen Stellen (vor allem im Bereich der > Internationalisierung) schon üblich ist. In C++ auch z.B. std::placeholders::_1 u.s.w.
Beitrag #6937706 wurde vom Autor gelöscht.
Jörg W. schrieb: > MaWin schrieb: >> Prefix durch Unterstrich klar trennen, wie Python und Rust es >> beherrschen > > Ist in C23 ein Apostroph (in C++ wohl auch). Unterstrich hat man nicht > genommen, weil es ein legaler Bezeichner ist, der auch an einigen > Stellen (vor allem im Bereich der Internationalisierung) schon üblich > ist. > > Also > #define S_IXOTH 0'000'001 /* X for other */ > > geht dann dort. In C++ wäre der Unterstrich nich eindeutig.
1 | int x = 0x00_ff; |
Das gleiche Problem hätte man, falls man Literale mit der oben erwähnte 36er Basis mit einem Prefix (hier 0q) einführen möchte.
1 | int x = 0q00s; |
oder um es etwas deutlicher zu machen ein Fall der auch in C zu Problemen führen würde
1 | int x = 0q00l; |
MaWin schrieb: >>>> 0o_101 > 265 > 3>>> 0x_101 > 4257 > 5>>> 0b_101 > 65 Schön dass es so einheitlich ist ;-)
1 | >>> bin(5) |
2 | '0b101' |
3 | >>> hex(255) |
4 | '0xff' |
5 | >>> print(oct(8)) |
6 | 0o10 |
Rolf M. schrieb: > Ja, C++ hat das (und den Präfix 0b für Binary) mit C++14 eingefügt. Der > Apostroph ist aber eher für die Gruppierung der Ziffern z.B. in > 3er-Gruppen gedacht und darf nun gerade nicht direkt nach einem 0x oder > 0b kommen. 0x'101 ist also nicht erlaubt, 0x1'01 schon. Das Detail war mir gerade nicht bewusst. Wobei, 0'000177 geht dann ja trotzdem. ;-) Dass das Gruppierungszeichen vor allem der Tausendergruppierung dient, ist mir klar, andererseits hat man natürlich bei anderen Basen eh andere Vorzüge (Hex-Zahlen dann bspw. eher aller vier Stellen), und meines Wissens ist es gewissermaßen ein "NOP", es wird also keinerlei weitere Semantik dran gebunden.
Rolf M. schrieb: > Ja, C++ hat das (und den Präfix 0b für Binary) mit C++14 eingefügt. Der > Apostroph ist aber eher für die Gruppierung der Ziffern z.B. in > 3er-Gruppen gedacht und darf nun gerade nicht direkt nach einem 0x oder > 0b kommen. 0x'101 ist also nicht erlaubt, 0x1'01 schon. Gibt es für das nicht erlauben einen triftigen Grund? Warum sollte das erste Zeichen anders behandelt werden als die übrigen? Das ist eine ähnliche Inkonsistenz wie die Sonderbehandlung einer 0 am Anfang einer Dezimalzahl.
Jörg W. schrieb: > MaWin schrieb: >> Prefix durch Unterstrich klar trennen, wie Python und Rust es >> beherrschen > > Ist in C23 ein Apostroph (in C++ wohl auch). Unterstrich hat man nicht > genommen, weil es ein legaler Bezeichner ist, der auch an einigen > Stellen (vor allem im Bereich der Internationalisierung) schon üblich > ist. Meines Wissens nach war ein Grund nicht den Unterstrich zu nehmen, dass der Unterstrich bei Hexadezimalzahlen nicht von einem C++ user-defined literal suffix unterscheidbar wäre.
Philipp Klaus K. schrieb: > Meines Wissens nach war ein Grund nicht den Unterstrich zu nehmen, dass > der Unterstrich bei Hexadezimalzahlen nicht von einem C++ user-defined > literal suffix unterscheidbar wäre. Ah OK. Hatte ich mir dann falsch gemerkt. Ich fand den Apostroph erstmal etwas ungewöhnlich, aber der ist ja in manchen Zahlenschreibweisen auch sonst wohl üblich.
Jobst Q. schrieb: > Rolf M. schrieb: >> Ja, C++ hat das (und den Präfix 0b für Binary) mit C++14 eingefügt. Der >> Apostroph ist aber eher für die Gruppierung der Ziffern z.B. in >> 3er-Gruppen gedacht und darf nun gerade nicht direkt nach einem 0x oder >> 0b kommen. 0x'101 ist also nicht erlaubt, 0x1'01 schon. > > Gibt es für das nicht erlauben einen triftigen Grund? Ich denke, weil es eben zur logischen Gruppierung der eigentlichen Ziffern dient und daher nur zwischen diesen gedacht ist. Für Dezimalzahlen geht es im übrigen ja auch nicht, weil sonst nicht klar wäre, ob '1' das Zeichen oder die Zahl sein soll. > Warum sollte das erste Zeichen anders behandelt werden als die übrigen? Das erste Zeichen wird nicht anders behandelt. Der Präfix für die Basis wird anders behandelt. > Das ist eine ähnliche Inkonsistenz wie die Sonderbehandlung einer 0 am > Anfang einer Dezimalzahl. Eine 0 am Anfang einer Dezimalzahl gibt es in C nicht. Jörg W. schrieb: > Wobei, 0'000177 geht dann ja trotzdem. ;-) Ja, das geht. Vielleicht haben sie gedacht, dass 0x und 0b ja schon von sich aus genug Trennung zwischen Präfix und dem eigentlichen Wert bieten, während die 0 das nicht so direkt tut. Aber da kann ich nur mutmaßen. > Dass das Gruppierungszeichen vor allem der Tausendergruppierung dient, > ist mir klar, andererseits hat man natürlich bei anderen Basen eh andere > Vorzüge (Hex-Zahlen dann bspw. eher aller vier Stellen), und meines > Wissens ist es gewissermaßen ein "NOP", es wird also keinerlei weitere > Semantik dran gebunden. Ja, richtig. Man muss es nicht zwingend alle 3 Ziffern machen. Es muss zwischen zwei Hochkommas lediglich mindestens eine Ziffer stehen. Man kann also z.B. auch Vierergruppen machen oder alle Ziffern einzeln durch Hochkommas trennen, wenn man will.
Jobst Q. schrieb: > Rolf M. schrieb: >> Ja, C++ hat das (und den Präfix 0b für Binary) mit C++14 eingefügt. Der >> Apostroph ist aber eher für die Gruppierung der Ziffern z.B. in >> 3er-Gruppen gedacht und darf nun gerade nicht direkt nach einem 0x oder >> 0b kommen. 0x'101 ist also nicht erlaubt, 0x1'01 schon. > > Gibt es für das nicht erlauben einen triftigen Grund? Warum sollte das > erste Zeichen anders behandelt werden als die übrigen? Einen triftigen Grund gibt es dafür nicht, aber es ist so konsistenter: Ein Integer-Literal setzt sich zusammen aus einem optionalen Präfix (0x oder 0b), einer Ziffernfolge und einem optionalen Suffix. Ein Apostroph darf nicht am Anfang oder am Ende der Ziffernfolge stehen, weil das Literal sonst bei nicht vorhandenem Präfix und Suffix mit einem Character-Literal verwechselt werden könnte. Diese Regel gilt aus Konsistenzgründen auch für Zahlen mit Präfix oder Suffix, auch wenn dort keine Verwechslungsgefahr besteht. Da das Apostroph als Trennzeichen zwischen Ziffern gedacht ist, ist das auch keine große Einschränkung. Dabei ist zu beachten, dass die führende 0 einer Oktalzahl kein Präfix, sondern Bestandteil der Ziffernfolge ist, denn wäre die 0 ein Präfix, würde das Literal 0 nur aus dem Präfix bestehen, und die Ziffernfolge wäre leer, also undefiniert. Um die Zahl Null auszudrücken, müsste man deswegen 00 schreiben, was natürlich nicht erwünscht ist. Weil aber 0 kein Präfix, sondern die erste Ziffer der Zahl ist, verstößt ein Apostroph direkt nach dieser 0 (wie bspw. in 0'123) nicht gegen die obige Regel. > Das ist eine ähnliche Inkonsistenz wie die Sonderbehandlung einer 0 am > Anfang einer Dezimalzahl. Die führende 0 zur Kennzeichnung von Oktalzahlen hat historische Gründe: Ursprünglich kannte C (wie auch dessen Vorgänger B) keine Hexadezimal-, sondern nur Dezimal- und Oktalzahlen. Das betraf sowohl Integer-Literale als die Formatierung mit printf. Ein Integer-Literal war unabhängig von der Basis einfach definiert als eine nichtleere Folge von Ziffern. Damals waren deswegen auch in Oktalzahlen die Ziffern 8 und 9 explizit erlaubt. Aus dem "C Reference Manual" von Ritchie: "The digits 8 and 9 have octal value 10 and 11 respectively." Syntaktisch gab es also erst einmal keinen Unterschied zwischen Dezimal- und Oktalzahlen, was die lexikalische Analyse des Quellcodes vereinfachte. Erst bei der Auswertung der Ziffernfolge zu einem Zahlenwert kam die Basis ins Spiel, wobei an dieser Stelle das einzig mögliche Unterscheidungsmerkmal das Vorhandensein einer ansonsten redundanten führenden 0 war. Wenn man die Vorgeschichte nicht kennt, mutet das aus heutiger Sicht natürlich ziemlich schräg an :)
:
Bearbeitet durch Moderator
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.