1

I have been reading "The C Programming Language" book by "KnR", and i've come across this statement: "plain chars are signed or unsigned"

  1. So my question is, what is a plain char and how is it any different from signed char and unsigned char?
  2. In the below code how is 'myPlainChar' - 'A' different from 'mySignChar' - 'A' and 'myUnsignChar' - 'A'?
  3. Can someone please explain me the statement "Printable char's are always positive".

Note: Please write examples and explain. Thank you.

{
    char myChar = 'A';
    signed char mySignChar = 'A';
    unsigned char myUnsignChar = 'A';
}
Martín Zaragoza
  • 1,717
  • 8
  • 19
  • 1
    It would be nice to post the third question, as a new question. It is not very related to the first two. If you do, I will retract my close vote. – gsamaras Aug 21 '18 at 13:12
  • Related: [Difference between byte and char in C](https://stackoverflow.com/a/1592748/1115360). – Andrew Morton Aug 21 '18 at 13:14
  • [Why is char not compatible with signed char or unsigned char?](https://stackoverflow.com/q/12769500/995714) – phuclv Aug 21 '18 at 13:15
  • "Printable char's are always positive" That's just false, isn't it? If anything, the unprintable ones would be the ones that are always in the positive range in most encodings (because the ISO encodings at least don't add any unprintable characters in addition to the ASCII ones), right? – sepp2k Aug 21 '18 at 13:22

5 Answers5

2

There are signed char and unsigned char. Whether char is signed or unsigned by default depends on compiler and its settings. Usually it is signed.

i486
  • 6,491
  • 4
  • 24
  • 41
  • "Usually it is signed" makes it seem like the unsigned variant is unusual, and it depends on how you measure "usually". – Ian Abbott Aug 21 '18 at 15:56
  • 1
    @IanAbbott If it is signed in 90% of cases, this is "usually". GCC + VC for example. – i486 Aug 21 '18 at 18:16
  • 1
    Maybe, maybe not. If you measure it by market share where ARM-based Android phones dominate the operating system market, then "unsigned" wins. So it depends how you measure "usually". – Ian Abbott Aug 22 '18 at 12:54
1

There is only one char type, just like there is only one int type.

But like with int you can add a modifier to tell the compiler if it's an unsigned or a signed char (or int):

signed char   x1;  // x1 can hold values from -128 to +127 (typically)
unsigned char x2;  // x2 can hold values from 0 to +255 (typically)
signed int    y1;  // y1 can hold values from -2147483648 to +2147483647 (typically)
unsigned int  y2;  // y2 can hold values from 0 to +4294967295 (typically)

The big difference between plain unmodified char and int is that int without a modifier will always be signed, but it's implementation defined (i.e. it's up to the compiler) if char without a modifier is signed or unsigned:

char x3;  // Could be signed, could be unsigned
int  y3;  // Will always be signed
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • `signed` and `unsigned` can be used on their own, so I don't think it is correct to call them modifiers. – Ian Abbott Aug 21 '18 at 14:35
  • 1
    @IanAbbott `signed` and `unsigned` on their own are really just aliases for `signed int` and `unsigned int` (respectively). – Some programmer dude Aug 21 '18 at 15:12
  • Not really. Rather, certain legal combinations of `signed`, `unsigned`, `char`, `short`, `int`, and `long` or `long long` produce certain, unqualified integer types, some of which are identical. – Ian Abbott Aug 21 '18 at 15:45
  • @IanAbbott I had the same idea but hesitated; I know this is about C, not C++, but a simple check in C++ was to overload a function for signed, unsigned and plain char and call with an argument of each. Would it compile? Yes. What did the compiler choose? Each of the respective functions, i.e. even though char is functionally and implementationally identical to one of the signed/unsigned types, the C++ compiler treats it as distinct type and not as an alias. Does C have specific wording for the character type relations? [Oh, the link in a comment to the OP quotes Note 35 in C99.] – Peter - Reinstate Monica Aug 22 '18 at 09:20
  • @IanAbbott Check out n.m's answer which clarifies the point: `signed int` is an alias to `int`, but `char` is a type distinct from all others. The test is to assign pointers to the various types to each other. In C++ there is also ODR with overloaded functions: you cannot have both `f(int)` and f(signed int)` but you can have `f(char)` and `f(signed char)` on my system with signed chars). – Peter - Reinstate Monica Aug 22 '18 at 12:15
  • @PeterA.Schneider I agree completely with n.m.'s answer, and agree that `signed int` is exactly the same type as `int`. The disagreement here is just about terminology. FWIW, the standard refers to `signed` and `unsigned` as *type specifiers* and as *keywords*, nothing else. – Ian Abbott Aug 22 '18 at 12:26
  • 1
    @IanAbbott `int` can differ from `signed int` with bit fields. In that case `int` may be signed or unsigned. – chux - Reinstate Monica Aug 22 '18 at 15:33
  • @chux Thanks, I'd forgotten about that. – Ian Abbott Aug 22 '18 at 15:39
  • Discussing `int` does not well answer OP's question about `char`. `signed int a` and `int b` are the same type of objects. `signed char d` and `char e` are different types of objects - even if `char` is _signed_. – chux - Reinstate Monica Aug 22 '18 at 16:25
1

Plain char is the type spelled char without signed or unsigned prefix.

Plain char, signed char and unsigned char are three distinct integral types (yes, character values are (small) integers), even though plain char is represented identically to one of the other two. Which one is implementation defined. This is distinct from say int : plain int is always the same as signed int.

There's a subtle point here: if plain char is for example signed, then it is a signed type, and we say "plain char is signed on this system", but it's still not the same type as signed char.

The difference between these two lines

signed char mySignChar = 'A';
unsigned char myUnsignChar = 'A';

is exactly the same as the difference between these two lines:

signed int mySignInt = 42;
unsigned int myUnsignInt = 42;

The statement "Printable char's are always positive" means exactly what it says. On some systems some plain char values are negative. On all systems some signed char values are negative. On all systems there is a character of each kind that is exactly zero. But none of those are printable. Unfortunately the statement is not necessarily correct (it is correct about all characters in the basic execution character set, but not about the extended execution character set).

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • "but it's still *not* the same type as `signed char`" - in what way (on a "char defaults to signed" system) can the two types be distinguished ? – psmears Aug 21 '18 at 13:52
  • 1
    @psmears Their run-time behaviour is exactly the same, but for example `char*` and `signed char*` are different pointer types that can only be converted to each other with an explicit cast. So if a function is declared as `int func(const signed char*)`, you cannot call it `func("abc")`, the compiler will complain. – n. m. could be an AI Aug 21 '18 at 14:04
  • Ah yes, good point about the pointer conversions, I'd only been thinking about the raw types :) – psmears Aug 21 '18 at 16:05
  • Interesting clarification of the difference between character and the other integer types. – Peter - Reinstate Monica Aug 22 '18 at 12:10
  • @n.m. i understand everything you said, but what exactly is the fine difference? – shaik nisar ahmed Aug 22 '18 at 17:49
  • @shaiknisarahmed Suppose you are on a 64-bit system. `short`, `int`, `long` and `long long` will be usually 16, 32 and 64 bit long, so two of the types will have the same length (normally either `int` and `long` will be 32 bit, or `long` and `long long` will be 64 bit). So you have two types which behave exactly the same, have exact same representation, and yet they are different types. Same story here. – n. m. could be an AI Aug 22 '18 at 21:17
  • #include int fun(const signed char*); int main() { fun("hello"); } int fun(const signed char* a) { printf("%s\n",a); return 0; } ->The compiler doesn't complain, and i'm using gcc compiler. – shaik nisar ahmed Aug 23 '18 at 11:52
  • @shaiknisarahmed Use -Wall. – n. m. could be an AI Aug 23 '18 at 12:50
0

How many char types are there in C?

There is one char type. There are 3 small character types: char, signed char, unsigned char. They are collectively called character types in C.

char has the same range/size/ranking/encoding as signed char or unsigned char, yet is a distinct type.


  1. what is a plain char and how is it any different from signed char and unsigned char?

They are 3 different types in C. A plain char char will match the same range/size/ranking/encoding as either singed char or unsigned char. In all cases the size is 1.


2 .how is myPlainChar - 'A' different from mySignChar - 'A' and myUnsignChar - 'A'?

myPlainChar - 'A' will match one of the other two.
Typically mySignChar has a value in the range [-128...127] and myUnsignChar in the range of [0...255]. So a subtraction of 'A' (typically a value of 65) will result a different range of potential answers.


  1. Can someone please explain me the statement "Printable char's are always positive".

Portable C source code characters (the basic execution character set) are positive so printing a source code file only prints characters of non-negative values.

When printing data with printf("%c", some_character_type) or putc(some_character_type) the value, either positive or negative is converted to an unsigned char before printing. Thus it is a character associated with a non-negative value that is printed.

C has isprint(int c) which "tests for any printing character including space". That function is only valid for values in the unsigned char range and the negative EOF. isprint(EOF) reports 0. So only non-negative values pass the isprint(int c) test.

C really has no way to print negative values as characters without undergoing a conversion to unsigned char.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • if char has the same range as of signed char then i.e -128 - +127 then what is the narrow difference that plain char has from signed char? -> As size for all the three is same i.e 1 byte, and same encoding too. – shaik nisar ahmed Aug 22 '18 at 18:06
  • @shaiknisarahmed "if char has the same range as of signed char ... what is the narrow difference that plain char has from signed char?" Both types have the same size (1), same range, rank (_integer conversion rank_) and encoding (2's complement, 1s' complement, sign-magnitude). In C, 2 distinct types may share the same properties. The difference is that they remain distinct types. See `_Generic(a)` for a way to distinguish `a`: is it type `char` or type `signed char`? – chux - Reinstate Monica Aug 22 '18 at 18:48
-3

I think it means char without 'unsigned' in front of it ie:

unsigned char a;

as opposed to

char a; // signed char

So basically a variable is always signed (for integers and char) unless you use the statement 'unsigned'.

That should answer the second question as well.

The third question: Characters that are in the ascii set are defined as unsigned characters, ie the number -60 doesn't represent a character, but 65 does, ie 'A'.

imqqmi
  • 423
  • 2
  • 9