Bei einem Placement new oder std::construct_at sollte doch der Compiler einfach die Adresse zuweisen und keine statische Initialisierung machen. Wenn ich den nachfolgenden Code im Compiler Explorer https://gcc.godbolt.org/ eingebe zeigt mir der GCC 12.2.noeabi bei beiden Varianten statischen Initialisierungscode an. Warum ?
Optionen : -std=c++20 -Og
Weil deine Variablen nicht constinit/constexpr sind und daher eben Laufzeit-initialisiert werden. Eigentlich müsstest du "constinit" hinzufügen, aber reinterpret_cast ist in constant expressions nicht erlaubt.
placement-new bzw construct_at ist eigentlich eh das falsche Werkzeug, du willst ja keinen Konstruktor auf den Peripherie-Registern aufrufen!
Man muss den Cast auf die Laufzeit verschieben, und im constant expression Kontext halt nur mit dem Integer hantieren. z.B. so:
Die Variablen gpio_A und gpio_B sind leere Dummys und belegen keinen Speicher, erst beim Aufruf des Pfeil-Operators erfolgt der Cast. Also eben zur Laufzeit, nur durch das Inlinen wird es dann effizient.
Sieht auf den ersten Blick ein klitzeklein wenig einfacher aus weil auf die Trennung verzichtet wird, ebenso auf die statische Variable. Es wird trotzdem gleiche Maschinencode erzeugt. Mit -Os oder -Oz wird's sogar noch kleiner.
Sieht auf den ersten Blick ein klitzeklein wenig einfacher aus
Gefällt mir nicht so ganz weil es so keinen nicht-templatisierten "gpio_type" gibt. Dadurch kann man kein "gpio_type*" als Funktionsparameter übergeben o.ä.
dann muss ich aber jetzt einmal blöd fragen, warum meckert dann der Compiler nicht? Also man kann sich ja nicht über etwas aufregen, was angeblich falsch sein soll, was jedoch funktioniert. Ich verstehe das Problem das mein Code nicht auf Linux kompilierbar ist, dass habe ich verstanden. Nur dann muss der Compiler meckern und die Vorgabe machen, wenn es überall gleichgezogen kompilieren sollen.
Kann ich dir nicht sagen. Weil \P und \A keine Control-Codes sind und auf P bzw. A abgebildet werden? Frag die Compilerbauer.
Also man kann sich ja nicht über etwas aufregen, was angeblich
falsch sein soll, was jedoch funktioniert.
Die Logik ist:
Code is korrekt => Code funktioniert
und
Code funktioniert nicht => Code ist nicht korrekt
"Code is inkorrekt" ist also nicht hinreichend dafür, dass er /nicht/ funktioniert. Die falsche Folgerung
Code funktioniert => Code ist korrekt
ist wohl der mit Abstand am weitesten verbreitete Denkfehler im Softwarebereich. So auch hier. Aber spätestens wenn du ein (anderes) Problem hast und jemandem den Code gibts, um das Problem nachzuvollziehen, kann der Fehler akut werden. Zum Beipiel wenn dein Kollege unter Linux, HPUX, SunOS, ... arbeitet.
Ich ahne worauf die Diskussion hinauslaufen wird.
Ich kürze das ab.
So richtig bewusst provokant aus der Hüfte geschossen. :-)
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Ich befürchte, es könnte eine lange Unterhaltung werden. ;-)
Nichts, das war ja der Punkt. Es gibt in C gewisse mit \ eingeleitete Sequenzen wie \n für ein Newline. \P und \A gibt es aber nicht.
Bei #include gibt's davon aber extra eine Ausnahme. Man kann also z.B. schreiben:
1
#include"a\b.txt"
um eine Datei namens a\b.txt einzubinden, aber nicht:
1
fopen("a\b.txt","rt");
um eine solche Datei zu öffnen, da \b das Backspace-Zeichen ist. Damit wird die Datei dann also nicht gefunden. Und wenn man es mit a\c.txt versucht, gibt's gar einen Fehler vom Compiler, da es keine Escape-Sequenz \c gibt.
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Verstehen tut es den durchaus, aber eben als Escape-Zeichen und nicht als Verzeichnis-Trenner. So war das in C und unter unixoiden Systemen schon lange, bevor Windows, oder auch DOS, überhaupt existiert hat.
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Linux ist sehr wohl fähig Backslashes im Pfad nicht nur zu erkennen. sondern sie zudem korrekt zu benutzen.
1
ls "Peter Pan"
1
ls Peter\ Pan
funktioniert zB. beides. Und ja, man kann selbstverständlich auch ASCII Ctrl-Chars unterbringen, sollte man dieses seltsame Bedürfnis verspüren.
Es liegt an Windows, dass man ihm jeden Stuss vorsetzen kann.
Slash, Backslash, Groß, Klein, Windows frisst eine Menge Zeug und es macht eine Menge irrer Annahmen um das Geraffel irgendwie zum Laufen zu bringen.
Altlasten aus der Zeit der Altvorderen.
Das schöne bei Linux ./. was-anderes-Flamewars ist die extreme Einsicht, die die beiden Seiten jeweils aufbringen, indem sie ihre Seite der Dinge als die einzig mögliche und einzig richtige darstellen.
Das schöne bei Linux ./. was-anderes-Flamewars ist die extreme
Einsicht,
die die beiden Seiten jeweils aufbringen, indem sie ihre Seite der Dinge
als die einzig mögliche und einzig richtige darstellen.
Macht keiner. ›Einzig möglich‹ ist ja durch Windows schon widerlegt.
›Einzig richtig‹ wohl auch nicht, das ist durch andere Systeme widerlegt.
Wenn man aber der Ansicht ist, dass es egal ist ob man ›\‹ oder ›/‹ oder gar beides bunt gemischt benutzt, dann stimme ich dir zu.
Wenn man "ABC, "abc","AbC",… als gleich ansieht, dann stimme ich dir zu.
PS. Ist der Explorer mittlerweile in der Lage mit einer einzelnen Operation die Groß/Kleinschreibung (umbenennen) einer Datei durchzuführen, oder braucht es dazu immer noch zwei Operationen?
Damit meine ich übrigens, dass in den Anfängen zunächst erst 8.3(immer Groß) zulässig war. Dann ging's etwas länger (zumindest stark begrenzt länger), dann kam Groß/Klein dazu, dann ging's noch länger, dann gab's eine Zeit während der die Dateinamen/Pfadnamen Begrenzungen nicht sauber in den SDKs definiert waren, usw.
Irgendwann zeitlich dazwischen — das wird sicherlich jemand besser wissen als ich — konnte man plötzlich ›\‹ UND ›/‹ verwenden.
Womöglich wird der ganze (Pfad-)String (ob nun richtig oder falsch) einfach an das Betriebssystem zur Öffnung übergeben und auf etwaige Fehler überprüft. Und da liefert Windows halt ein OK. Das wäre jetzt zumindest meine Vermutung. Ergo prüft ›C‹** evtl. nicht wirklich was da im (Pfad-)String drin steht.
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Warum ist Windows unfähig den Slash im Pfad zu verstehen?
Ist es ja gar nicht. Schon MS-DOS 3.x konnte den Slash intern als Pfad-Trenner benutzen. Lediglich command.com und dessen Nachfolger haben den Slash als Options-Zeichen benutzt (statt Bindestrich in Unix) und brauch(t)en daher den Backslash.
Intern (auf Ebene der Systemaufrufe) funktioniert der Vorwärtsstrich, weshalb man im Sinne der Portabilität gut daran tut, diesen auch bei Windows durchweg innerhalb von Programmen zu verwenden. Ganz nebenbei umgeht man dadurch potenzielle Probleme der Fehlinterpretation von durch Backslash eingeleiteten Escape-Sequenzen – nicht nur bei C, auch andere Sprachen haben dieses Konzept ja.
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Der Slash als Trenner in Pfaden existiert bereits seit 1970 (UNIX), da gab es noch keine Betriebssysteme von Microsoft. Warum MS sich dann für den Backslash entschied, könnte an Jörgs Erklärung liegen: MS hat den Slash für Kommando-Optionen genutzt - vermutlich, bevor überhaupt Unterverzeichnisse in MS-DOS eingeführt wurden. Das war damals schon eine krasse Fehlentscheidung.
Warum unterstützt der GCC Backslashes in Include-Pfaden unter Windows? Wahrscheinlich aus Mitleid - um es vorsichtig auszudrücken.
P.S.
Browser wie Edge, Chrome und Firefox unterstützen auch URLs mit Backslashes wie zum Beispiel:
1
https:\\www.mikrocontroller.net\topic\580316
Obwohl Backslashes meines Wissens nach in URLs gar nicht so funktionieren dürfen - siehe RFC 3986.
Der / als Pfad-Trenner ist eine Degign-Entscheidung von C/C++.
Nö. C interessiert sich überhaupt nicht für Pfadtrenner. Bei #include sagt es einfach, dass es systemspezifisch ist, wie der dort angegebene Name in einen Dateinamen übersetzt wird oder ob da überhaupt echte Dateien dahinter stehen.
Jedenfalls war die Entscheidung, die Quellen unabhängig vom Host-System
zu halten, eine gute.
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Warum ist Windows unfähig den Slash im Pfad zu verstehen?
Ist es ja gar nicht. Schon MS-DOS 3.x konnte den Slash intern als
Pfad-Trenner benutzen. Lediglich command.com und dessen Nachfolger
haben den Slash als Options-Zeichen benutzt (statt Bindestrich in Unix)
und brauch(t)en daher den Backslash.
Nicht nur das, sondern sie haben auch erlaubt, das trennende Leerzeichen zwischen Programmname und Parameter weglassen zu können, wie z.B.:
1
dir/p
Wäre ein trennendes Leerzeichen erforderlich, dann wäre es auch kein Problem gewesen, den / als Verzeichnistrenner in command.com zu unterstützen.
Warum unterstützt der GCC Backslashes in Include-Pfaden unter Windows?
Wahrscheinlich aus Mitleid - um es vorsichtig auszudrücken.
Ich vermute eher, weil die anderen Compiler für Windows es auch können und weil man, um es nicht zu können, extra zusätzlichen Code einbauen müsste. Tut man nichts dagegen, dann funktioniert es automatisch.
Warum unterstützt der GCC Backslashes in Include-Pfaden unter Windows?
Wahrscheinlich aus Mitleid - um es vorsichtig auszudrücken.
Naja es macht schon Sinn das native Pfad-Format des jeweiligen Host-OS zu verstehen. Diskutabel ist, ob bei Ausgaben auch (standardmäßig) das native Format verwendet werden sollte, beim Compiler also z.B. in den Pfaden der Debug-Informationen.
CMake unterstützt z.B. bei manchen Eingabe-Pfaden auch unter Windows ausschließlich Unix-Trennzeichen, während z.B. VS Code den Pfad zum aktuellen Projekt in der Kommandozeilen-Substitution mit Backslashes generiert, sodass man das nicht direkt an CMake übergeben kann - sehr ungünstig!
Außerdem sieht "C:/Users/ich/..." schon irgendwie komisch aus 😉
Warum unterstützt der GCC Backslashes in Include-Pfaden unter Windows?
Ich denke, die Erklärung ist viel einfacher, als die meisten vermuten: weil ihn das gar nicht interessiert. Alles zwischen den Spitzklammern oder Anführungszeichen nach #include wird am Ende an das OS weitergereicht. Deshalb funktionieren die Vorwärtsstriche eben auch unter Windows (und sowas wie #include <sys/stat.h> gab es meiner Erinnerung nach schon in den ersten Versionen von Turbo-C), denn die Syscalls dort kommen ja damit klar.
If the characters ', , ", //, or /* occur in the sequence between the < and > delimiters, the behavior is undefined. Similarly, if the characters ', , //, or /* occur in the sequence between the " delimiters, the behavior is undefined.
If the characters ', , ", //, or /* occur in the sequence between the <
and > delimiters, the behavior is undefined. Similarly, if the
characters ', , //, or /* occur in the sequence between the "
delimiters, the behavior is undefined.
Hmm, interessant. Das heißt, dass man bei #include den \ als Verzeichnistrenner in C eigentlich gar nicht verwenden darf.
Die praktisch gleiche Regel gibt es in C++ übrigens auch.
Und da es hier ja eigentlich um C++ geht noch 2.8 aus ISO 14882:
If either of the characters ’ or , or either of the character sequences /* or // appears in a q-char-sequence or a h-char-sequence, or the character " appears in a h-char-sequence, the behavior is undefined
Wohlgemerkt: "undefined", nicht "implementation-defined"!
D.h.
1
#include<sys\stat.h>
ist in C++ (anders als in C99) erlaubt, wohingegen die Bedeutung von
Und in C++23 ist es wieder anders (das Zitat oben war für C++03):
The appearance of either of the characters ’ or \ or of either of the character sequences /* or // in a q-char-sequence or an h-char-sequence is conditionally-supported with implementation-defined semantics, as is the appearance of the character " in an h-char-sequence.[13]
Thus, a sequence of characters that resembles an escape sequence can result in an error, be interpreted as the character corresponding to the escape sequence, or have a completely different meaning, depending on the implementation.
Z.B. der Header sys/stat.h wird von IEEE 1003 definiert. Mit /.
Mit Standard-Header meinte ich jetzt explizit die aus dem C- und dem C++-Standard. Bei POSIX sieht's natürlich wieder anders aus. Windows ist aber nicht POSIX-konform.
Windows war es aber mal ab Windows NT - hauptsächlich, um überhaupt noch Aufträge von der US-Regierung zu erhalten. Die Posix-Konformität wurde aber mit Windows XP bzw. Windows 2003 wieder entfernt.
Warum ist Linux unfähig den Backslash im Pfad zu verstehen?
Warum ist Windows unfähig den Slash im Pfad zu verstehen?
Sorry, aber genau diese Frage stellt sich unter Windows nicht. Es kann mit Slash und Backslash umgehen. Kann man auch in der DOS-Box bzw. im cmd prompt ausprobieren. Ansonsten hätte ich den include Pfad wie gezeigt überhaupt nicht schreiben können und ich hätte nicht diese provokante Frage gestellt.
zur Beruhigung der Massen.
Da ich nur unter Windows programmiere fiel mir das eben noch nicht auf bzw. dachte es wäre egal. Bewusst um jemanden zu ärgern habe ich das jedenfalls nicht gemacht. Ich werde in Zukunft / verwenden als Pfadtrenner. Glücklicherweise kann Windows damit umgehen. ;-) Was man nicht alles als Windows User macht damit Linuxer glücklich sind. ;-)
Was man nicht alles als Windows User macht damit Linuxer glücklich sind. ;-)
Backslashes bei #include waren schon undefined behavior bevor es
Linux(er) gab.
Irgendwas stimmt an der Aussage nicht.
a) unter Windows sind Backslash Standard
b) wird der Pfad von include vom Dateisystem vom OS aufgelöst
Ansonsten würde es mit Backslash unter Windows und include nicht funktionieren. Man kann nicht etwas unverständliches dem Compiler übergeben, der wiederum auf das Dateisystem mit falscher Pfadangabe zugreift. Irgendwann wäre mir ein "undefined behavior" aufgefallen in den Jahren. Weil ansonsten hätte es direkt beim Kompilieren eine Fehlermeldung gegeben mit Pfad nicht gefunden o.ä.. Irgendwelche versteckten Fehler zur Laufzeit kann es dabei nicht geben.
Der zitierte Spruch war auch anders gemeint. Windows User haben mit Backslash und include keine Problem zu erwarten. Im include gibt es keine Escape-Zeichen. Das Problem mit Backslash beginnt, wie von Johann richtig erkannt, wenn man es mit Backslash unter Linux verwenden möchte. Dann muss man alle Pfadangaben korrigieren. Das heißt ich als Windows User korrigiere die Pfadangaben erstmal primär für potentielle Linuxer. Weil sich das bei mir nicht auswirkt. Das war der Witz im Spruch. ;-) Bei mir korrigiert das OS Dateisystem den Slash zurück in Backslash für die Pfadangabe und Dateizugriff. Weil unter Linux ist Slash Standard und unter Windows ist Backslash Standard. Irgendein OS User muss die Hürde nehmen.
Weil aber ein Escape-Zeichen den Backslash benötigt, verwendet man beim Programmieren besser Slash als Pfadtrenner. Das heißt der Windows User muss die Gedanken zusammennehmen.
Irgendwas stimmt an der Aussage nicht.
a) unter Windows sind Backslash Standard
b) wird der Pfad von include vom Dateisystem vom OS aufgelöst
In den C- und C++-Standards ist das, was man hinter #include in spitzen Klammern oder Anführungszeichen angibt, gar nicht als Pfadname spezifiziert. Also sind Deine beiden Beobachtungen für ISO 9899 (C) und ISO 14882 (C++) nicht relevant.
Vielmehr ist das "Argument" von #include irgendetwas, das auf implementationsspezifische Weise auf einen Header oder eine Quelldatei abgebildet wird. Z.B. braucht keine Datei namens stdio.h zu existieren solange
Die Programmiersprachen C und C++ (ohne Beachtung der Standardbibliotheken) kennen das Konzept "Pfadnamen" gar nicht. Es gibt auch keine Unterverzeichnisse oder ähnliches, keine Komponenten von Pfadnamen, keine Trennzeichen. Wie Dein Lieblingsbetrübssystem Pfadnamen definiert, ist also völlig irrelevant. Es gelten die Regeln, die ISO 9899 bzw. ISO 14882 für #include festlegen.
1
#include"include\Pin\AVRxDB32_PinRegister.h"
ist erst seit (ungefähr, mein Archiv ist lückenhaft) C++23 nicht mehr völlig undefiniert.
Aber "..." bei #include "..." ist gar kein string-literal sondern ein Anführungszeichen gefolgt von einer q-char-sequence gefolgt von einem Anführungszeichen. Interessanter wird es bei
1
#define N "subdir\neuedatei.h"
2
#include N
Da gilt zunächst die Syntax von pp-token (also hier string-literal) und dann die von q-char-sequence.
Backslashes bei #include waren schon undefined behavior bevor es
Linux(er) gab.
Irgendwas stimmt an der Aussage nicht.
a) unter Windows sind Backslash Standard
Das ist für C nicht relevant. Wie schon ein paar mal erwähnt, gab es Windows noch gar nicht, als das für C definiert wurde, und kein Mensch hat \ als Verzeichnistrenner verwendet.
b) wird der Pfad von include vom Dateisystem vom OS aufgelöst
Nein, er wird auf impelmetationsspezifische Weise vom Compiler in Dateinamen oder ggf. auch was anderes transformiert, um damit auf den Header zuzugreifen. Diese Transformation kann natürlich auch daraus bestehen, dass der Compiler den Namen 1:1 an die Betriebssystem-Funktion weitergibt, aber das ist dann Sache des Compilers, nicht des Standards.
Ansonsten würde es mit Backslash unter Windows und include nicht
funktionieren. Man kann nicht etwas unverständliches dem Compiler
übergeben, der wiederum auf das Dateisystem mit falscher Pfadangabe
zugreift. Irgendwann wäre mir ein "undefined behavior" aufgefallen in
den Jahren.
Undefined behavior heißt nicht, dass der Standard verlangt, dass es nicht funktioniert, sondern nur, dass aus Sicht des Standards beliebiges passieren kann, wenn du es versuchst. Ab dem Zeitpunkt, zu dem du undefiniertes Verhalten hervorrufst, darf der Compiler machen, was immer er will, und das nicht nur mit dem spezifischen Konstrukt, der es hervorgerufen hat, sondern mit dem gesamten Programm. Wie gesagt heißt das nicht, dass etwas komisches passieren muss, aber es darf, und der Compiler ist dann immer noch standardkonform.
Weil ansonsten hätte es direkt beim Kompilieren eine
Fehlermeldung gegeben mit Pfad nicht gefunden o.ä.. Irgendwelche
versteckten Fehler zur Laufzeit kann es dabei nicht geben.
Auch das entspricht nicht dem, was Undefined Behavior bedeutet.
Der zitierte Spruch war auch anders gemeint. Windows User haben mit
Backslash und include keine Problem zu erwarten. Im include gibt es
keine Escape-Zeichen. Das Problem mit Backslash beginnt, wie von Johann
richtig erkannt, wenn man es mit Backslash unter Linux verwenden möchte.
Dann muss man alle Pfadangaben korrigieren. Das heißt ich als Windows
User korrigiere die Pfadangaben erstmal primär für potentielle Linuxer.
Das eigentlich nicht direkt mit Linux zu tun. Es gibt eigentlich nur die folgenden Dinge, die wesentlich sind:
Verwendest du /, dann ist das nach C-Standard zwar implementationsspezifisch (was die headernamen aber eh immer sind), aber es ist ok. Es funktioniert auf so ziemlich allem, was den Compiler ausführen kann, und das geht auch über Linux hinaus (z.B. MacOS, FreeBSD, Solaris, …)
Wenn du dagegen \ verwendest, ist das nach C-Standard und C++ vor C++23 offiziell undefiniertes Verhalten. Es funktioniert außerdem ausschießlich unter Windows. Irgendeinen Vorteil gegenüber der anderen Variante hat es nicht.
Dazu kommt noch, dass das mit dem \ ja so nur bei #include funktioniert. Beim Öffnen von Dateien dagegen tut's dann (mit String literals) so nicht mehr.
Beim Öffnen von Dateien dagegen tut's dann (mit String literals) so
nicht mehr.
… oder man müsste dann generell alle Backslashes doppelt notieren, das wäre wieder sicher. Vorwärtsstriche sind dann sicherlich die einfachere (und besser lesbare) Variante. ;-)
Ja, kenn ich noch. Ich war zwar glaub noch nicht dabei, als das entstanden ist, aber kurz danach. Hab selbst oft genug in comp.lang.c "Neulingen" von nasalen Dämonen erzählt … mann, bin ich alt. 🤔