Connect with us

Entwicklung & Code

Type Punning in C++: Der saubere Ansatz mit C++20



Portrait von Andreas Fertig

Portrait von Andreas Fertig

Andreas Fertig ist erfahrener C++-Trainer und Berater, der weltweit Präsenz- sowie Remote-Kurse anbietet. Er engagiert sich im C++-Standardisierungskomitee und spricht regelmäßig auf internationalen Konferenzen. Mit C++ Insights ( hat er ein international anerkanntes Tool entwickelt, das C++-Programmierenden hilft, C++ noch besser zu verstehen.

Der heutige Beitrag widmet sich der Typumwandlung via Type Punning in C++. Das habe ich jahrelang gemacht, als ich im Bereich Embedded-Software gearbeitet habe, und andere haben das schon lange vor mir gemacht. Laut Standard ist das zu 100 Prozent verboten. Trotzdem weiß ich, dass viele Embedded-Geräte mit Type Punning gebaut werden, obwohl es nicht nur verboten ist, sondern auch zu unbestimmtem Verhalten (Undefined Behavior, UB) führt.

Weiterlesen nach der Anzeige

Anhand des folgenden Codes möchte ich klären, was ich unter Type Punning verstehe und warum es sich dabei um undefiniertes Verhalten in C++ handelt.


float pi = 3.14f;  // #A

// #B
uint32_t first = static_cast(pi);

// #C
uint32_t second = *reinterpret_cast(&pi);


Der Code soll die Bitdarstellung des float in #A in eine Ganzzahl umwandeln. Es geht nicht darum, den Wert 3,14 in eine Ganzzahl umzuwandeln, die 3 wäre. Das Ziel ist es, die Bitdarstellung (0x4048f5c3) zu erhalten.

Ich stelle mir zwei Versuche vor, die ich oft gesehen habe. Der erste in #B verwendet ein static_cast. Dieser Versuch lässt sich zwar kompilieren und ist zu 100 Prozent gültiges C++, aber das Ergebnis ist nicht das, was du suchst, da du die konvertierten Werte erhältst und am Ende die Zahl 3 in first hast.

Der zweite Versuch muss natürlich cleverer sein, und ich würde sagen, dass #C tatsächlich clever aussieht. Dieser Code holt sich zuerst die Adresse des float und nutzt dann reinterpret_cast, um den float-Zeiger in einen int-Zeiger umzuwandeln, und schließlich den frisch erhaltenen Zeiger auf einen int zu dereferenzieren. Du beugst einfach die Regeln von C++ (und übrigens auch von C) so weit, dass der Compiler die Umwandlung zulässt. Erfolg!

Weiterlesen nach der Anzeige

Nun ja – dass der Code kompiliert wird, ist nur der erste Schritt! Als Nächstes muss er verknüpft (linked) werden, was ebenfalls erfolgreich ist. Dann muss der Code das tun, was du geplant hast. Hier wird es knifflig. Du hast gerade Code geschrieben, der undefiniertes Verhalten enthält.

Indem du bei der Konvertierungssequenz zu clever warst, hast du dem Compiler die Möglichkeit gegeben, die Zuweisung zu second zu optimieren. Das hängt im Wesentlichen mit der Lebensdauer von Objekten und den entsprechenden Regeln zusammen. Grob gesagt wurde der int, den du in #C zuweist, aus Sicht des Compilers nie aktiv. Es gibt keinen Konstruktor und keine zulässige Konvertierungssequenz, die den Compiler auf den Beginn der Lebensdauer aufmerksam machen würde. Eine perfekte Gelegenheit für den Compiler, uns einige Anweisungen zu ersparen, indem er diese gesamte Zuweisung optimiert.

Ich habe Kunden, die aus diesem Grund die Optimierungsstufe nicht höher als -O1 einstellen.

Als ich über den Teil „zur Rettung“ nachdachte, kam mir die Fernsehserie Baywatch in den Sinn, in der die Rettungsschwimmer mit roten Rettungsbojen (Safety Buoy) ins Wasser rannten.

Okay, zurück vom Strand ins Büro. C++20 hat eine Rettungsboje namens std::bit_cast für den oben beschriebenen Fall. Anstatt eine Menge Code zu schreiben, um den Compiler zur gewünschten Konvertierungssequenz zu verleiten, wende std::bit_cast auf die gleiche Weise an wie first static_cast. Dein Code sieht dann folgendermaßen aus:


const float    pi  = 3.14f;
const uint32_t pii = std::bit_cast(pi);


Wie du siehst, kommt std::bit_cast wirklich wie ein static_cast daher. Du gibst den Zieldatentyp in den spitzen Klammern und die Quellvariable oder den Quellwert als Argument an. Als Ergebnis erhältst du ein Objekt vom Zieldatentyp.

Intern nutzt std::bit_cast memcpy, um die Quellbits in den Zielpuffer zu kopieren, bevor dieser zurückgegeben wird. Das funktioniert, weil memcpy seit C++20 vom Standard als Element anerkannt ist, das die Lebensdauer eines Objekts startet.

Wenn du mit einer Situation wie der am Anfang des Beitrags konfrontiert bist, solltest du sicherheitshalber immer std::bit_cast bevorzugen, wenn du kannst.


(rme)



Source link

Entwicklung & Code

Deep Dive Spring Modulith Teil 1: Fachliche Module im Fokus


Mit Spring Modulith ist es möglich, Spring-Boot-Anwendungen in fachliche Module aufzuteilen, die über klare Schnittstellen verfügen, per Events kommunizieren und sich isoliert testen lassen. Die Architektur der Module lässt sich automatisiert überwachen und dokumentieren. Diese Artikelserie stellt Spring Modulith, dessen Version 2.0 im November 2025 erschien, in zwei Teilen vor. Der erste Teil zeigt die Grundlagen der Modul- und Event-basierten Architektur. Teil 2 wirft unter anderem einen Blick auf die Testmöglichkeiten der Module.

Weiterlesen nach der Anzeige


Nils Hartmann

Nils Hartmann

Nils Hartmann ist freiberuflicher Softwareentwickler und Coach mit den Schwerpunkten Java im Backend und React im Frontend, wozu er auch Workshops und Trainings gibt.

Spring Boot ist eine typische Wahl bei der Entwicklung von Java-basierten Anwendungen. Um den damit entwickelten Code auch langfristig beherrschbar zu halten, werden oft Architekturmuster wie Schichten-, Hexagonal- oder Onion-Architektur angewendet. Diese Muster teilen die Anwendung aber oft nur in eher technische Bestandteile auf, um beispielsweise eine Entkopplung von eingesetzten Datenbanken oder anderen externen Systemen zu ermöglichen. In der klassischen Layer-Architektur greifen beispielsweise Controller auf Services und Services auf Repositorys zu, nicht aber Repositorys auf Services oder Controller.

In der Hexagonal-Architektur werden einzelne Komponenten wie UI- und Persistenzschicht sowie der fachliche Anwendungskern über „Ports“ und „Adapter“ voneinander separiert. Das soll die Domain-Logik von technischen Details, wie der Anbindung an eine konkrete Datenbank, trennen. Außerdem sollen diese Architekturstile ermöglichen, dass einzelne Teile der Anwendung isoliert testbar und jederzeit austauschbar sind, etwa beim Wechsel der Datenbank. Spring Modulith geht einen anderen Weg.

Modulith ist ein Kofferwort aus „modularer Monolith“. Die Anwendung wird als Monolith entwickelt, ist aber intern nach streng fachlichen Modulen (auch Slices genannt) aufgeteilt. Der potenziell komplexe fachliche Kern einer Anwendung soll so in beherrschbare kleinere Einheiten zerteilt werden, die in sich abgeschlossen mit klaren Schnittstellen versehen sind und alles enthalten, was zur Umsetzung der jeweiligen Fachlichkeit nötig ist. Änderungen an fachlichen Anforderungen haben somit im besten Fall nur Auswirkungen auf genau ein Modul. Die Module einer Anwendung können nach den oben genannten Architekturstilen implementiert werden, müssen es aber nicht. Ähnlich wie bei Microservices kann auch hier pro Modul – jedenfalls in einem gewissen Rahmen – die jeweils passende Architektur gewählt werden.

Dieser Artikel stellt Spring Modulith anhand der Beispielanwendung „Plantify“ vor. Plantify bietet die Möglichkeit, dass Kunden ihre Pflanzen pflegen lassen. Dazu registrieren sie zunächst ihre Pflanzen. Plantify legt für jede Pflanze Pflegeaufgaben an, die dann ein Dienstleister abarbeitet. Für die durchgeführten Aufgaben schickt Plantify regelmäßig eine Rechnung an die Kunden. Die Kommunikation mit der Anwendung findet über eine HTTP-API statt. Der Sourcecode der Beispielanwendung ist auf GitHub zu finden.


Blättersprösslinge im Frühling

Blättersprösslinge im Frühling

(Bild: buraratn/123rf)

Bei der Online-Konferenz betterCode() Spring stehen am Vormittag sichere Anwendungen mit Spring Security und die Integration von KI mit Spring AI im Fokus. Der Nachmittag widmet sich Spring Boot und zeigt die Neuerungen von Version 4 im Zusammenspiel mit Java 25, Tipps zur Integration von Containern sowie in der Praxis bewährte Spring Boot Hacks.

Weiterlesen nach der Anzeige

Um Spring Modulith in der eigenen Anwendung zu verwenden, fügt man dessen Starter-Paket in der eigenen Maven- oder Gradle-Konfiguration hinzu. Das reicht schon aus, damit Spring Modulith die Packages in der Anwendung unterschiedlich klassifiziert und behandelt. Alle Packages, die sich direkt unterhalb des Root-Packages befinden (das ist das Package mit der Klasse SpringBootApplication), betrachtet Spring Modulith als „Application Module“. Technisch bleiben es zwar weiterhin normale Java-Packages, aber Spring Modulith legt der Verwendung dieser Application Modules einige Regeln auf. Zum Beispiel darf es zwischen den Application Modules nicht zu direkten oder indirekten zirkulären Abhängigkeiten kommen.

In der Plantify-Anwendung gibt es etwa direkt unterhalb des Root-Packages nh.plantify drei Packages plant, care und billing. Diese drei Packages interpretiert Spring Modulith als Application Modules. In der Anwendung greift das Application Module plant auf care zu (z. B. um die Pflegeaufgaben einer neuen Pflanze anzulegen). Außerdem greift care auf billing zu, um die Einrichtungsgebühr zu berechnen. Diese Abhängigkeiten sind erlaubt, denn sie zeigen nur in eine Richtung. Würde die Anwendung aber erweitert, sodass eine Klasse aus dem billing-Modul auf das plant-Modul zugreifen würde, ergäbe sich daraus eine zirkuläre Abhängigkeit. Diese erkennt und verbietet Spring Modulith, da diese Art der Abhängigkeit oft zu Problemen in der weiteren Entwicklung führt.

Das Einhalten der Regeln lässt sich mit Spring Modulith auf mehreren Wegen kontrollieren und sicherstellen. Zum einen kann Spring Modulith sie bei jedem Start der Anwendung prüfen und bei Verstößen Fehler ausgeben. Das kostet allerdings Zeit und findet im Entwicklungsprozess erst spät statt. Alternativ lässt sich ein JUnit-Test implementieren, der die Regel überprüft. Ein entsprechendes Beispiel findet sich in Listing 1.


class PlantifyModuleTest {

    static ApplicationModules modules = ApplicationModules.of(PlantifyApplication.class);

    @Test
    void verifyModules() {
        modules.verify();
    }

    @Test
    void writeDocumentationSnippets() {
        new Documenter(modules)
            .writeModulesAsPlantUml();
    }
}


Listing 1: Die Modulstruktur wird im JUnit-Test überprüft und visualisiert

Die Klasse ApplicationModules repräsentiert die erkannten Application Modules im übergebenen Paket. Die verify-Methode stellt innerhalb des Tests sicher, dass alle Regeln eingehalten werden. Bei Verstößen schlägt der Test mit einer ausführlichen Fehlermeldung fehl (siehe Abbildung 1).


Der Unit-Test deckt Regelverstöße (zirkuläre Abhängigkeiten) auf (Abb. 1).

Der Unit-Test deckt Regelverstöße (zirkuläre Abhängigkeiten) auf (Abb. 1).

Der Unit-Test deckt Regelverstöße (zirkuläre Abhängigkeiten) auf (Abb. 1).

Diese Tests werden mit allen anderen „normalen“ Tests einer Anwendung kontinuierlich ausgeführt, sodass Probleme schnell auffallen. Die ApplicationModules-Klasse kann außerdem die Modulstruktur als C4-Diagramm ausgeben, aus der auch die Art der Verwendungen eines Moduls hervorgeht (dazu später mehr). Die Visualisierung der Plantify-Module zu diesem Zeitpunkt ist in Abbildung 2 zu sehen.


Die initiale Modulstruktur, visualisiert von Spring Modulith (Abb. 2)

Die initiale Modulstruktur, visualisiert von Spring Modulith (Abb. 2)

Die initiale Modulstruktur, visualisiert von Spring Modulith (Abb. 2).

Neben dem Verbot zirkulärer Abhängigkeiten wendet Spring Modulith noch eine andere Regel von Haus aus an: Alle Unterpakete in einem Application Module gelten als „intern“. Klassen daraus dürfen zwar innerhalb des Application Module beliebig verwendet werden, allerdings ist der Zugriff darauf aus anderen Modulen verboten. Mit anderen Worten: Das Root-Package eines Application Module ist dessen öffentliche API. Nur die Public-Klassen stehen anderen Modulen zur Verfügung. Der oben gezeigte Test Case prüft auch die Einhaltung dieser Regel. Zusätzlich können IDEs wie IntelliJ, Eclipse oder VS Code mit den entsprechenden Plug-ins diese Regeln prüfen und direkt im Quellcode anzeigen. Abbildung 3 zeigt ein entsprechendes Beispiel in Eclipse mit den Spring Tools.


Die Verwendung interner Klassen zeigt Eclipse mit den Spring Tools als Fehler an (Abb. 3)

Die Verwendung interner Klassen zeigt Eclipse mit den Spring Tools als Fehler an (Abb. 3)

Die Verwendung interner Klassen zeigt Eclipse mit den Spring Tools als Fehler an (Abb. 3).

Hier wird aus dem CareTaskService, der sich im Modul care befindet, auf die Klasse InvoiceGenerator zugegriffen, die sich in dem Unterpaket invoice des billing-Moduls befindet. Ohne Spring Modulith wäre der Zugriff aus Java-Sicht regelkonform, da die Klasse InvoiceGenerator public ist, und somit von allen Packages aus verwendet werden darf.



Source link

Weiterlesen

Entwicklung & Code

programmier.bar: Data-Aware Architecture mit Matthias Niehoff


In dieser Podcastfolge spricht die programmier.bar mit Matthias Niehoff, Head of Data und Principal Data Architect bei Codecentric, über das Konzept der Data-Aware Architecture. Dabei handelt es sich weniger um ein klar abgegrenztes Architektur-Pattern als um einen Denkansatz: Daten sollen von Beginn an systematisch in Architekturentscheidungen einbezogen werden, insbesondere mit Blick auf analytische Nutzung. Ziel ist es, Daten verlässlich, nachvollziehbar und strukturiert nutzbar zu machen, ohne die Anwendung selbst unnötig komplex zu gestalten.

Weiterlesen nach der Anzeige

Matthias Niehoff beschreibt, wie sich Data-Aware Architecture in der Praxis umsetzen lässt. Dazu zählen unter anderem die frühzeitige Einbindung von Analytics-Teams, die Definition von Data Contracts sowie die Etablierung sogenannter Data Products als stabile Schnittstellen zwischen Entwicklungsteams und Datenkonsumenten. Diese sollen dokumentierte, validierbare Datenflüsse ermöglichen, die auch bei Änderungen in den zugrunde liegenden Systemen konsistent bleiben. Entscheidend sei dabei ein pragmatischer Ansatz: Weder große Plattformen noch zusätzliche Tools lösen das Grundproblem allein, vielmehr komme es auf klare Verantwortlichkeiten und Abstimmung zwischen Teams an.

Empfohlener redaktioneller Inhalt

Mit Ihrer Zustimmung wird hier ein externer Inhalt geladen.

Ein besonderer Fokus liegt auf dem Umgang mit Legacy-Systemen. Matthias Niehoff erläutert, wie bestehende Schnittstellen analysiert, Verantwortlichkeiten geklärt und Data Contracts schrittweise eingeführt werden können – auch in gewachsenen Systemlandschaften. Abschließend ordnet er die Rolle von KI im Kontext Data-Aware Architecture ein, etwa als Unterstützung bei semantischem Kontext-Engineering oder als direkter Konsument strukturierter Daten.


Aufmacher bcc Modern Architecture

Aufmacher bcc Modern Architecture

(Bild: RONY/Adobe Stock)

Die Online-Konferenz betterCode() Modern Architecture von iX und dpunkt.verlag am 25. März 2026 stellt aktuelle Konzepte der Softwarearchitektur vor wie Clean Architecture, Hexagonale Architektur oder Microservices. Design mit LLMs ist ebenso ein Thema wie Architektur für eine digitale Souveränität.

Die aktuelle Ausgabe des Podcasts steht auch im Blog der programmier.bar bereit: „Data-Aware Architecture mit Matthias Niehoff“. Fragen und Anregungen gerne per Mail oder via Mastodon, Bluesky, LinkedIn oder Instagram.

Weiterlesen nach der Anzeige


(mdo)





Source link

Weiterlesen

Entwicklung & Code

Zu viel Copilot: Gentoo wechselt von GitHub zu Codeberg


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Gentoo Linux eröffnet eine Präsenz auf der Berliner Code-Verwaltungsplattform Codeberg. Sie ist ein erster Schritt der Loslösung von GitHub. Die neuen Repositories auf Codeberg sind ein Spiegel der Struktur, die Gentoo selbst hostet.

Weiterlesen nach der Anzeige

Im Gentoo-Blog heißt es, dass Codeberg eine Alternative zu GitHub sein soll, aber auch „Teil einer graduellen Migration weg von GitHub“. Bereits im Januar hatte Gentoo angekündigt, sich von der Microsoft-Plattform lösen zu wollen: „Goodbye Github, welcome Codeberg“. Als Grund nennt der Anbieter: „Hauptsächlich wegen der fortgesetzten Versuche, eine Copilot-Nutzung für unsere Repositories zu erzwingen.“

Viele Projekte beklagen, dass Coding-Assistenten die Arbeit der Maintainer stören, weil KI-Nutzer immer mehr schlechte und wertlose Pull Requests einreichen. Gerade Open-Source-Projekte – wie auch Gentoo – lehnen daher oft KI-generierten Code ab. Außerdem stören sich viele Open-Source-Betreiber an der Nutzung ihrer Daten für das Training der Modelle, was sich GitHub ausdrücklich vorbehält.

Aus den gleichen Gründen hatte Zig im Dezember letzten Jahres GitHub den Rücken gekehrt und curl sich vom Bug-Bounty-Programm verabschiedet. Curl-Maintainer Stenberg beklagt, dass 95 Prozent der Einreichungen wertlos waren.

Codeberg ist im Gegensatz zu Microsofts GitHub ein nicht kommerzieller Verein mit Sitz in Berlin. Der Betrieb geschieht ausschließlich durch die Community. Technische Basis ist die Plattform Forgejo, die wiederum Git verwendet und ähnliche Funktionen zur gemeinsamen Code-Verwaltung wie GitHub bietet.

Gentoo setzt den AGit-Workflow (eine Methode zum direkten Einreichen von Änderungen ohne Fork) zum Klonen und für Pull Requests ein:

Weiterlesen nach der Anzeige


git clone git@git.gentoo.org:repo/gentoo.git
cd gentoo
git remote add codeberg ssh://git@codeberg.org/gentoo/gentoo
git checkout -b my-new-fixes
git push codeberg HEAD:refs/for/master -o topic="$title"


Weitere Commits lassen sich mit demselben Topic nachtragen. Das Haupt-Repository hostet Gentoo selbst: Sowohl die neue Präsenz auf Codeberg als auch die alte, noch existierende auf GitHub sind nur Spiegel, die der Bequemlichkeit der Kontributoren dienen sollen.


(who)



Source link

Weiterlesen

Beliebt