Le caractère est-il signé ou non signé par défaut?

158

Dans le livre "Référence complète de C", il est mentionné qu'il charest par défaut non signé.

Mais j'essaie de vérifier cela avec GCC ainsi que Visual Studio. Il le prend comme signé par défaut.

Laquelle est correcte?

C apprenant
la source
5
Le seul ouvrage de référence en C auquel je fais confiance est "C: A Reference Manual" de Harbison & Steele ( careencemanual.com ). Bien sûr, la norme est le dernier mot, mais elle n'est pas très lisible et ne donne que la moindre information sur les utilisations pré-standard et courantes (c'est-à-dire POSIX) qui sont en dehors de la norme. Harbison & Steele est assez lisible, détaillé et probablement plus correct que la plupart des références. Cependant, ce n'est pas non plus un tutoriel, donc si vous êtes dans les premières étapes de l'apprentissage, ce n'est probablement pas une bonne chose à faire.
Michael Burr
15
Je pense que le livre que vous lisez est C: The Complete Reference , par Herbert Schildt. D'après une critique de ce livre ( accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm ): Je ne recommanderai pas ce livre (trop d'entre vous accordent trop d'importance à mes opinions) mais Je ne pense pas qu'il mérite le même opprobre qui a été légitimement jeté à certains de ses autres travaux. Comme Michael le dit, une bien meilleure référence est Harbison & Steele .
Alok Singhal
Mes deux cents ici: Parce que charpeut être non signé, en règle générale, utilisez un intpour lire une valeur en utilisant getchar(), qui pourrait retourner EOF. EOFest généralement défini comme -1ou une autre valeur négative, dont le stockage dans un unsignedn'est pas ce que vous voulez. Voici la déclaration: extern int getchar();BTW, cette recommandation vient également du livre "C: A Reference Manual".
Maxim Chetrusca
6
La seule référence C en laquelle j'ai confiance est ISO / IEC 9899: 2011 :-)
Jeff
3
@MaxChetrusca Bon conseil mais mauvaise justification: même sur le charcas signé , il faudrait l'utiliser intpour stocker la valeur de retour.
Antti Haapala

Réponses:

204

Le livre est faux. La norme ne spécifie pas si plain charest signé ou non signé.

En fait, la norme définit trois types distincts: char, signed charet unsigned char. Si vous #include <limits.h>regardez ensuite CHAR_MIN, vous pouvez savoir si plain charest signedou unsigned(si CHAR_MINest inférieur à 0 ou égal à 0), mais même dans ce cas, les trois types sont distincts en ce qui concerne la norme.

Notez que charc'est spécial de cette manière. Si vous déclarez une variable car intelle équivaut à 100% à la déclarer comme signed int. Ceci est toujours vrai pour tous les compilateurs et architectures.

Alok Singhal
la source
1
@Alok: la même chose n'est pas vraie pour certains autres types de données, par exemple intsignifie signed inttoujours, non? À part char, dans quels autres types de données ont la même confusion C?
Lazer
8
@eSKay: oui, charc'est le seul type qui peut être signé ou non signé. intéquivaut à signed intpar exemple.
Alok Singhal
28
Il y a une raison hystérique, euh, historique à cela - au début de la vie de C, le «standard» a été inversé au moins deux fois, et certains compilateurs populaires tôt ont fini dans un sens et d'autres dans l'autre.
Hot Licks
9
@AlokSinghal: Il est également défini par l'implémentation si un champ de bits de type intest signé ou non signé.
Keith Thompson
@KeithThompson merci pour la correction. J'ai tendance à oublier certains détails sur les types de champs de bits car je ne les utilise pas beaucoup.
Alok Singhal
67

Comme le souligne Alok , la norme laisse cela à la mise en œuvre.

Pour gcc, la valeur par défaut est signée, mais vous pouvez la modifier avec -funsigned-char. remarque: pour gcc dans Android NDK, la valeur par défaut est non signée . Vous pouvez également demander explicitement des caractères signés avec -fsigned-char.

Sur MSVC, la valeur par défaut est signée mais vous pouvez la modifier avec /J.

R Samuel Klatchko
la source
2
Il est intéressant de noter que la description de Schildt ne correspond pas au comportement de MSVC puisque ses livres sont généralement destinés aux utilisateurs de MSVC. Je me demande si MS a changé la valeur par défaut à un moment donné?
Michael Burr
1
Je pensais que cela ne dépendait pas du compilateur, mais de la plate-forme. Je pensais que char était laissé comme troisième type de "type de données de caractère" pour se conformer à ce que les systèmes à l'époque utilisaient comme caractères imprimables.
Spidey
10
La documentation GCC dit que cela dépend de la machine: " Chaque type de machine a une valeur par défaut pour ce que doit être le caractère. C'est soit comme un caractère non signé par défaut ou comme un caractère signé par défaut. "
Deduplicator
1
Pouvez-vous s'il vous plaît fournir une source pour votre note que sur Android, la valeur par défaut est un caractère non signé?
phlipsy
1
@Spidey le standard C ne fait aucune distinction réelle entre les compilateurs, les plates-formes et les architectures CPU. Il les regroupe simplement sous «mise en œuvre».
plugwash
35

C99 N1256 draft 6.2.5 / 15 "Types" a ceci à dire à propos de la signature du type char:

La mise en œuvre doit définir char pour avoir la même plage, la même représentation et le même comportement que char signé ou char non signé.

et dans une note de bas de page:

CHAR_MIN, défini dans <limits.h>, aura l'une des valeurs 0ou SCHAR_MIN, et cela peut être utilisé pour distinguer les deux options. Quel que soit le choix effectué, charest un type distinct des deux autres et n'est pas compatible avec l'un ou l'autre.

Michael Burr
la source
7

Selon le livre The C Programming Language de Dennis Ritchie, qui est le livre standard de facto pour ANSI C, les caractères simples signés ou non signés dépendent de la machine, mais les caractères imprimables sont toujours positifs.

Ravi Rathi
la source
9
Ce n'est pas nécessairement le cas que les caractères imprimables soient toujours positifs. La norme C garantit que tous les membres du jeu de caractères d'exécution de base ont des valeurs non négatives.
Keith Thompson
7

Selon la norme C, la signature de plain char est "définie par l'implémentation".

En général, les implémenteurs ont choisi celui qui était le plus efficace à implémenter sur leur architecture. Sur les systèmes x86, le caractère est généralement signé. Sur les systèmes armés, il n'est généralement pas signé (Apple iOS est une exception).

plugwash
la source
2
@plugwash Votre réponse a probablement été rejetée parce que Tim Post a perdu ses clés . Sérieusement cependant, vous ne devriez pas vous soucier d'un seul vote défavorable tant que vous êtes sûr que votre réponse est correcte (ce qui est le cas dans ce cas). Il m'est arrivé plusieurs fois de voir mes messages déclassés sans raison valable. Ne vous en faites pas, parfois les gens font des choses bizarres.
Donald Duck
1
Pourquoi le caractère signé est-il plus efficace sur x86? Des sources?
martinkunev
2

Selon «Le langage de programmation C ++» de Bjarne Stroustrup, char«l'implémentation est définie». Cela peut être signed charou unsigned charselon la mise en œuvre. Vous pouvez vérifier s'il charest signé ou non en utilisant std::numeric_limits<char>::is_signed.

BoQ
la source
9
C'est une question C. C ++ est un langage différent et les références C ++ n'ont aucune pertinence pour C.
MM
1

Maintenant, nous savons que la norme laisse cela à la mise en œuvre.

Mais comment vérifier un type est signedou unsigned, comme char?

J'ai écrit une macro pour faire ceci:

#define IS_UNSIGNED(t) ((t)~1 > 0)

et le tester avec gcc, clanget cl. Mais je ne suis pas sûr que ce soit toujours sans danger pour les autres cas.

南山 竹
la source
Quel est le problème avec CHAR_MIN <0 (ou WCHAR_MIN <0 pour wchar_t)?
Öö Tiib