Was bewirkt, dass ein Zeichen signiert oder unsigniert wird, wenn gcc verwendet wird?

 C Programming >> C-Programmierung >  >> Tags >> GCC
Was bewirkt, dass ein Zeichen signiert oder unsigniert wird, wenn gcc verwendet wird?


Was verursacht, wenn ein char in C (mit gcc) ist signiert oder unsigniert? Ich weiß, dass der Standard nichts übereinander schreibt und dass ich CHAR_MIN überprüfen kann und CHAR_MAX von limits.h, aber ich möchte wissen, was bei der Verwendung von gcc

übereinander auslöst

Wenn ich limits.h von libgcc-6 lese, sehe ich, dass es ein Makro __CHAR_UNSIGNED__ gibt was ein "Standard"-Zeichen mit oder ohne Vorzeichen definiert, aber ich bin mir nicht sicher, ob dies vom Compiler zu (seiner) Erstellungszeit festgelegt wird.


Ich habe versucht, GCCs vordefinierte Makros mit

aufzulisten
$ gcc -dM -E -x c /dev/null | grep -i CHAR
#define __UINT_LEAST8_TYPE__ unsigned char
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 0x7fffffff
#define __GCC_ATOMIC_CHAR_LOCK_FREE 2
#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2
#define __SCHAR_MAX__ 0x7f
#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)
#define __UINT8_TYPE__ unsigned char
#define __INT8_TYPE__ signed char
#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2
#define __CHAR16_TYPE__ short unsigned int
#define __INT_LEAST8_TYPE__ signed char
#define __WCHAR_TYPE__ int
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2
#define __SIZEOF_WCHAR_T__ 4
#define __INT_FAST8_TYPE__ signed char
#define __CHAR32_TYPE__ unsigned int
#define __UINT_FAST8_TYPE__ unsigned char

konnte aber __CHAR_UNSIGNED__ nicht finden


Hintergrund:Ich habe Code, den ich auf zwei verschiedenen Maschinen kompiliere:


Desktop-PC:



  • Debian GNU/Linux 9.1 (gestreckt)

  • gcc-Version 6.3.0 20170516 (Debian 6.3.0-18)

  • Intel(R) Core(TM) i3-4150

  • libgcc-6-dev:6.3.0-18

  • char ist signiert


Raspberry Pi3 :



  • Raspbian GNU/Linux 9.1 (gestreckt)

  • gcc-Version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1)

  • ARMv7-Prozessor Rev. 4 (v7l)

  • libgcc-6-dev:6.3.0-18+rpi

  • char ist unsigniert


Der einzige offensichtliche Unterschied ist also die CPU-Architektur...


Antworten:


Gemäß dem C11-Standard (lesen Sie n1570), char kann signed sein oder unsigned (Sie haben also tatsächlich zwei Geschmacksrichtungen von C). Was genau es ist, ist implementierungsspezifisch.


Einige Prozessoren und Befehlssatzarchitekturen oder binäre Anwendungsschnittstellen bevorzugen einen signed Zeichentyp (Byte) (z. B. weil er sich gut auf einige Maschinencodeanweisungen abbilden lässt), andere bevorzugen einen unsigned eins.


gcc hat sogar einige -fsigned-char oder -funsigned-char Option, die Sie fast nie verwenden sollten (weil eine Änderung einige Eckfälle beim Aufrufen von Konventionen und ABIs bricht), es sei denn, Sie kompilieren alles neu, einschließlich Ihrer C-Standardbibliothek.


Sie könnten feature_test_macros(7) und <endian.h> verwenden (siehe endian(3)) oder autoconf unter Linux, um herauszufinden, was Ihr System hat.


In den meisten Fällen sollten Sie portablen C-Code schreiben, der nicht von diesen Dingen abhängt. Und Sie können plattformübergreifende Bibliotheken (z. B. glib) finden, die Ihnen dabei helfen.


Übrigens gcc -dM -E -x c /dev/null ergibt auch __BYTE_ORDER__ usw., und wenn Sie ein vorzeichenloses 8-Bit-Byte wollen, sollten Sie <stdint.h> verwenden und seine uint8_t (portabler und besser lesbar). Und Standard-limits.h definiert CHAR_MIN und SCHAR_MIN und CHAR_MAX und SCHAR_MAX (Sie könnten sie auf Gleichheit vergleichen, um signed char zu erkennen s-Implementierungen), etc...


Übrigens sollten Sie sich um die Zeichencodierung kümmern, aber die meisten Systeme verwenden heute überall UTF-8. Bibliotheken wie libunistring sind hilfreich. Siehe auch dies und denken Sie daran, dass ein in UTF-8 codiertes Unicode-Zeichen praktisch mehrere Bytes umfassen kann (z. B. char -s).