Versteckte Funktionen von C

Lesezeit: 2 Minuten

Ich weiß, dass hinter allen C-Compiler-Implementierungen ein Standard steht, daher sollten keine versteckten Funktionen vorhanden sein. Trotzdem bin ich mir sicher, dass alle C-Entwickler versteckte/geheime Tricks haben, die sie ständig anwenden.

  • Es wäre großartig, wenn Sie/jemand die „Frage“ bearbeiten würde, um die Auswahl der besten versteckten Funktionen anzugeben, z. B. in den C#- und Perl-Versionen dieser Frage.

    – Donal Fellows

    26. Mai 2010 um 13:19 Uhr

int8_t
int16_t
int32_t
uint8_t
uint16_t
uint32_t

Dies ist ein optionales Element im Standard, aber es muss ein verstecktes Feature sein, da die Leute sie ständig neu definieren. Eine Codebasis, an der ich gearbeitet habe (und die ich vorerst immer noch tue), hat mehrere Neudefinitionen, alle mit unterschiedlichen Bezeichnern. Meistens ist es mit Präprozessor-Makros:

#define INT16 short
#define INT32  long

Usw. Es bringt mich dazu, mir die Haare auszureißen. Verwenden Sie einfach die verdammten Standard-Integer-Typedefs!

  • Ich denke, sie sind C99 oder so. Ich habe keinen tragbaren Weg gefunden, um sicherzustellen, dass diese vorhanden sind.

    – akauppi

    25. September 2008 um 19:25 Uhr

  • Sie sind ein optionaler Teil von C99, aber ich kenne keinen Compiler-Anbieter, der dies nicht implementiert.

    – Ben Collins

    25. September 2008 um 21:07 Uhr

  • stdint.h ist in C99 nicht optional, aber das Befolgen des C99-Standards ist anscheinend für einige Anbieter (Husten Microsoft).

    – Ben Combee

    22. Oktober 2008 um 17:54 Uhr

  • @Pete, wenn Sie anal sein wollen: (1) Dieser Thread hat nichts mit einem Microsoft-Produkt zu tun. (2) Dieser Thread hatte überhaupt nichts mit C++ zu tun. (3) So etwas wie C++ 97 gibt es nicht.

    – Ben Collins

    1. März 2009 um 21:20 Uhr

  • Schau mal rein amillionmonkeys.com/qed/pstdint.h — eine nahezu tragbare stdint.h

    – Gnud

    16. April 2009 um 14:16 Uhr

  • In 20 Jahren CI noch NIE erlebt!

    – Martin Beckett

    22. Juni 2009 um 14:55 Uhr

  • In C++ kann man es sogar überladen.

    – Wouter Lievens

    1. Juli 2009 um 10:45 Uhr

  • kann != sollte natürlich. Die Gefahr beim Überladen besteht darin, dass das Eingebaute bereits für alles gilt, einschließlich void, sodass die Kompilierung aufgrund fehlender verfügbarer Überladung niemals fehlschlägt. Dh gibt dem Programmierer viel Seil.

    – Aaron

    6. Juli 2009 um 17:45 Uhr

  • Das int innerhalb der Schleife funktioniert nicht mit C: Es ist eine C++-Verbesserung. Ist das “,” die gleiche Operation wie für (i=0,j=10;i

    – Aif

    26. November 2010 um 14:00 Uhr


Initialisierung der Struktur auf Null

struct mystruct a = {0};

Dadurch werden alle Strukturelemente auf Null gesetzt.

  • Es nullt jedoch nicht die Polsterung, falls vorhanden.

    – Mikeage

    1. März 2009 um 13:49 Uhr

  • @simonn, nein, es zeigt kein undefiniertes Verhalten, wenn die Struktur nicht ganzzahlige Typen enthält. memset mit 0 auf dem Speicher eines Float/Double ist immer noch Null, wenn Sie das Float/Double interpretieren (Float/Double sind absichtlich so gestaltet).

    – Trevor Boyd Smith

    11. Juni 2009 um 13:59 Uhr

  • @Andrew: memset/calloc tun “alle Bytes Null” (dh physikalische Nullen), was ja nicht für alle Typen definiert ist. { 0 } wird garantiert intilaize alles mit richtig logisch Nullwerte. Zeiger erhalten beispielsweise garantiert ihre richtigen Nullwerte, auch wenn der Nullwert auf der angegebenen Plattform liegt 0xBAADFOOD.

    – AnT steht zu Russland

    28. Oktober 2009 um 10:12 Uhr

  • @nvl: Du bekommst körperlich Null, wenn Sie einfach den gesamten vom Objekt belegten Speicher zwangsweise auf den Nur-Bits-Null-Zustand setzen. Das ist was memset macht (mit 0 als zweites Argument). Du erhältst logisch Null beim Initialisieren/Zuweisen 0 ( oder { 0 }) zum Objekt im Quellcode. Diese beiden Arten von Nullen führen nicht notwendigerweise zum gleichen Ergebnis. Wie im Beispiel mit Zeiger. Wenn Sie das tun memset auf einem Zeiger erhalten Sie a 0x0000 Zeiger. Aber wenn Sie zuweisen 0 zu einem Zeiger, erhalten Sie Nullzeigerwertwas auf der körperlichen Ebene sein könnte 0xBAADF00D oder irgendetwas anderes.

    – AnT steht zu Russland

    26. Februar 2010 um 16:29 Uhr


  • @nvl: Nun, in der Praxis ist der Unterschied oft nur konzeptionell. Aber theoretisch kann es praktisch jeder Typ haben. Zum Beispiel, double. Üblicherweise wird es gemäß dem IEEE-754-Standard implementiert, bei dem die logische Null und die physikalische Null gleich sind. Aber IEEE-754 wird von der Sprache nicht benötigt. Das kann also passieren, wenn Sie es tun double d = 0; (logische Null), physikalisch einige Bits im Speicher belegt durch d wird nicht null sein.

    – AnT steht zu Russland

    26. Februar 2010 um 19:17 Uhr

Funktionszeiger. Sie können eine Tabelle von Funktionszeigern verwenden, um z. B. schnelle Indirect-Threaded-Code-Interpreter (FORTH) oder Byte-Code-Dispatcher zu implementieren oder um OO-ähnliche virtuelle Methoden zu simulieren.

Dann gibt es versteckte Juwelen in der Standardbibliothek, wie qsort(),bsearch(), strpbrk(), strcspn() [the latter two being useful for implementing a strtok() replacement].

Eine Fehlfunktion von C ist, dass arithmetischer Überlauf mit Vorzeichen ein undefiniertes Verhalten (UB) ist. Wann immer Sie also einen Ausdruck wie x+y sehen, der beide signierte Ints sind, kann er möglicherweise überlaufen und UB verursachen.

  • Es nullt jedoch nicht die Polsterung, falls vorhanden.

    – Mikeage

    1. März 2009 um 13:49 Uhr

  • @simonn, nein, es zeigt kein undefiniertes Verhalten, wenn die Struktur nicht ganzzahlige Typen enthält. memset mit 0 auf dem Speicher eines Float/Double ist immer noch Null, wenn Sie das Float/Double interpretieren (Float/Double sind absichtlich so gestaltet).

    – Trevor Boyd Smith

    11. Juni 2009 um 13:59 Uhr

  • @Andrew: memset/calloc tun “alle Bytes Null” (dh physikalische Nullen), was ja nicht für alle Typen definiert ist. { 0 } wird garantiert intilaize alles mit richtig logisch Nullwerte. Zeiger erhalten beispielsweise garantiert ihre richtigen Nullwerte, auch wenn der Nullwert auf der angegebenen Plattform liegt 0xBAADFOOD.

    – AnT steht zu Russland

    28. Oktober 2009 um 10:12 Uhr

  • @nvl: Du bekommst körperlich Null, wenn Sie einfach den gesamten vom Objekt belegten Speicher zwangsweise auf den Nur-Bits-Null-Zustand setzen. Das ist was memset macht (mit 0 als zweites Argument). Du erhältst logisch Null beim Initialisieren/Zuweisen 0 ( oder { 0 }) zum Objekt im Quellcode. Diese beiden Arten von Nullen führen nicht notwendigerweise zum gleichen Ergebnis. Wie im Beispiel mit Zeiger. Wenn Sie das tun memset auf einem Zeiger erhalten Sie a 0x0000 Zeiger. Aber wenn Sie zuweisen 0 zu einem Zeiger, erhalten Sie Nullzeigerwertwas auf der körperlichen Ebene sein könnte 0xBAADF00D oder irgendetwas anderes.

    – AnT steht zu Russland

    26. Februar 2010 um 16:29 Uhr


  • @nvl: Nun, in der Praxis ist der Unterschied oft nur konzeptionell. Aber theoretisch kann es praktisch jeder Typ haben. Zum Beispiel, double. Üblicherweise wird es gemäß dem IEEE-754-Standard implementiert, bei dem die logische Null und die physikalische Null gleich sind. Aber IEEE-754 wird von der Sprache nicht benötigt. Das kann also passieren, wenn Sie es tun double d = 0; (logische Null), physikalisch einige Bits im Speicher belegt durch d wird nicht null sein.

    – AnT steht zu Russland

    26. Februar 2010 um 19:17 Uhr

Konstanten mit mehreren Zeichen:

int x = 'ABCD';

Dies setzt x zu 0x41424344 (oder 0x44434241je nach Architektur).

BEARBEITEN: Diese Technik ist nicht portierbar, insbesondere wenn Sie int serialisieren. Es kann jedoch äußerst nützlich sein, selbstdokumentierende Aufzählungen zu erstellen. z.B

enum state {
    stopped = 'STOP',
    running = 'RUN!',
    waiting = 'WAIT',
};

Dies macht es viel einfacher, wenn Sie sich einen Rohspeicherauszug ansehen und den Wert einer Aufzählung bestimmen müssen, ohne ihn nachschlagen zu müssen.

  • Ich bin mir ziemlich sicher, dass dies kein tragbares Konstrukt ist. Das Ergebnis der Erstellung einer Konstante mit mehreren Zeichen ist implementierungsdefiniert.

    – Markus Bessey

    17. Oktober 2008 um 4:18 Uhr

  • Die “nicht portierbaren” Kommentare verfehlen den Punkt völlig. Es ist, als würde man ein Programm für die Verwendung von INT_MAX kritisieren, nur weil INT_MAX “nicht portabel” ist 🙂 Diese Funktion ist so portabel, wie sie sein muss. Die Multi-Char-Konstante ist eine äußerst nützliche Funktion, die eine lesbare Methode zum Generieren eindeutiger ganzzahliger IDs bietet.

    – AnT steht zu Russland

    28. Oktober 2009 um 10:36 Uhr

  • @ Chris Lutz – Ich bin mir ziemlich sicher, dass das abschließende Komma bis zu K & R zurückreicht. Es ist in der zweiten Auflage (1988) beschrieben.

    – Ferruccio

    28. Oktober 2009 um 11:15 Uhr

  • @Ferruccio: Sie müssen an das abschließende Komma in den aggregierten Initialisierungslisten denken. Was das nachgestellte Komma in Enum-Deklarationen angeht – es ist eine neue Ergänzung, C99.

    – AnT steht zu Russland

    28. Oktober 2009 um 17:59 Uhr

  • Du hast ‘HANG’ oder ‘BSOD’ vergessen 🙂

    – JBRWilkinson

    2. November 2009 um 16:30 Uhr

1423820cookie-checkVersteckte Funktionen von C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy