¿Qué hace que un carácter esté firmado o sin firmar cuando se usa gcc?

 C Programming >> Programación C >  >> Tags >> GCC
¿Qué hace que un carácter esté firmado o sin firmar cuando se usa gcc?


¿Qué causa si un char en C (usando gcc) está firmado o sin firmar? Sé que el estándar no dicta uno sobre el otro y que puedo verificar CHAR_MIN y CHAR_MAX de limites.h pero quiero saber qué desencadena uno sobre el otro cuando se usa gcc


Si leo limites.h de libgcc-6 veo que hay una macro __CHAR_UNSIGNED__ que define un carácter "predeterminado" firmado o sin firmar, pero no estoy seguro de si el compilador lo establece en (su) tiempo de compilación.


Traté de listar los makros predefinidos de GCC con


$ 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

pero no pude encontrar __CHAR_UNSIGNED__


Antecedentes:tengo un código que compilo en dos máquinas diferentes:


PC de escritorio:



  • Debian GNU/Linux 9.1 (extendido)

  • gcc versión 6.3.0 20170516 (Debian 6.3.0-18)

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

  • libgcc-6-dev:6.3.0-18

  • char está firmado


Frambuesa Pi3 :



  • Raspbian GNU/Linux 9.1 (extendido)

  • gcc versión 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1)

  • Procesador ARMv7 versión 4 (v7l)

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

  • char no está firmado


Así que la única diferencia obvia es la arquitectura de la CPU...


Respuestas:


Según el estándar C11 (léase n1570), char puede ser signed o unsigned (así que en realidad tienes dos sabores de C). Lo que es exactamente es específico de la implementación.


Algunos procesadores y arquitecturas de conjuntos de instrucciones o interfaces binarias de aplicaciones favorecen un signed tipo de carácter (byte) (por ejemplo, porque se asigna muy bien a alguna instrucción de código de máquina), otros favorecen un unsigned uno.


gcc tiene incluso algo de -fsigned-char o -funsigned-char opción que casi nunca debería usar (porque cambiarla rompe algunos casos de esquina en las convenciones de llamada y ABI) a menos que vuelva a compilar todo, incluida su biblioteca estándar de C.


Podrías usar feature_test_macros(7) y <endian.h> (vea endian(3)) o autoconf en Linux para detectar lo que tiene su sistema.


En la mayoría de los casos, debe escribir código C portátil, que no depende de esas cosas. Y puede encontrar bibliotecas multiplataforma (p. ej., glib) para ayudarlo en eso.


Por cierto gcc -dM -E -x c /dev/null también da __BYTE_ORDER__ etc., y si desea un byte de 8 bits sin firmar, debe usar <stdint.h> y su uint8_t (más portátil y más legible). Y limites estándar.h define CHAR_MIN y SCHAR_MIN y CHAR_MAX y SCHAR_MAX (podría compararlos por igualdad para detectar signed char s implementaciones), etc...


Por cierto, debería preocuparse por la codificación de caracteres, pero la mayoría de los sistemas actuales usan UTF-8 en todas partes. Las bibliotecas como libunistring son útiles. Vea también esto y recuerde que, en términos prácticos, un carácter Unicode codificado en UTF-8 puede abarcar varios bytes (es decir, char -s).