Why char in C is performing different behaviour? - c

I am a beginner and I am curious about char in C. I know that char takes only one character. If I inline initialize char like the below code:
#include <stdio.h>
int main() {
char c2 = 'ab';
printf("c2: %c\n", c2);
return 0;
}
It will output b. My first question is why b and why not a?
Again if I take input form console like the below code:
#include <stdio.h>
int main() {
char c3;
scanf("%c", &c3);
printf("c3: %c\n", c3);
return 0;
}
Now if I input ab then it will output a. Why now not giving output b as the first one (inline initialization)?
Please someone explain why this different behaviour is performing?

You can't fit 'ab' in a char, and trying to assign 'ab' to a char truncates it to the lower byte, 'b'.
Please, please turn your compiler warnings on and heed them; you can see these errors on Godbolt:
<source>: In function 'main':
<source>:4:15: warning: multi-character character constant [-Wmultichar]
4 | char c2 = 'ab';
| ^~~~
<source>:4:15: warning: overflow in conversion from 'int' to 'char' changes value from '24930' to '98' [-Woverflow]
98 is the ASCII value for b:
>>> chr(98)
'b'
For your second program, if you input 'ab', scanf with %c consumes 1 character, 'a'. (Other input remains in the input buffer and would be consumed by subsequent similar scanf calls.)

Compiling the first example may compile with warnings. e.g in gcc:
main.c: In function ‘main’:
main.c:4:15: warning: multi-character character constant [-Wmultichar]
4 | char c2 = 'ab';
| ^~~~
main.c:4:15: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘24930’ to ‘98’ [-Woverflow]
Since:
The value of an integer character constant containing more than one character (e.g., 'ab'), [...] is implementation-defined.
The warnings also suggests the implementation behaviour: 24930 = 0x6162 where 0x62 is ASCII 'b'. So the implementation behaviour is a matter of byte-order, then assignment of an int to a char, which assigns the least significant byte.
The behaviour of the second example is no surprise - input is not assignment or initialisation, and it is not a C language behaviour, but a system I/O behaviour. Input is buffered and requesting a single character input will take the first character from the first-in-first-out (FIFO) input queue. The first character when you enter 'a' followed by 'b' is of course 'a'.
A second input request would retrieve the 'b' whereas in the initialisation example the 'b' is simply discarded by the assignment. Comparing I/O behaviour with C language assignment behaviour are not at all comparable. The input is a FIFO queue of single characters, whereas 'ab' is an int (in this implementation).

This is compiler-specific, so called implementation-defined behavior.
From the C standard 6.4.4.4/2:
An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in 'x'.
Then 6.4.4.4/10, which happens to use the very same example as you:
An integer character constant has type int. The value of an integer character constant
containing a single character that maps to a single-byte execution character is the
numerical value of the representation of the mapped character interpreted as an integer.
The value of an integer character constant containing more than one character (e.g.,
'ab'), or containing a character or escape sequence that does not map to a single-byte
execution character, is implementation-defined. If an integer character constant contains
a single character or escape sequence, its value is the one that results when an object with
type char whose value is that of the single character or escape sequence is converted to
type int.
In the second example, the first character you place in stdin is the one read and the other is ignored. This has nothing to do with character constants but is simply how scanf works.

Related

Using int to print character constants [duplicate]

This question already has answers here:
Multi-character constant warnings
(6 answers)
Print decimal value of a char
(5 answers)
Closed 5 years ago.
I wrote the following program,
#include<stdio.h>
int main(void)
{
int i='A';
printf("i=%c",i);
return 0;
}
and I got the result as,
i=A
So I tried another program,
#include<stdio.h>
int main(void)
{
int i='ABC';
printf("i=%c",i);
return 0;
}
According to me, since 32 bits are used to store an int value and each of 'A', 'B' and 'C' have 8 bit ASCII codes which totals to 24 bits therefore 24 bits were stored in a 32 bit unit. So I expected the output to be,
i=ABC
but the output instead was
i=C
and I can't understand why?
'ABC' in this case is a integer character constant as per section 6.4.4.4.10 of the standard.
An integer character constant has type int. The value of an integer
character constant containing a single character that maps to a
single-byte execution character is the numerical value of the
representation of the mapped character interpreted as an integer. The
value of an integer character constant containing more than one
character (e.g.,'ab'), or containing a character or escape sequence
that does not map to a single-byteexecution character, is
implementation-defined. If an integer character constant contains a
single character or escape sequence, its value is the one that results
when an object with type char whose value is that of the single
character or escape sequence is converted to type int.
In this case, 'A'==0x41, 'B'==0x42, 'C'==0x43, and your compiler then interprets i to be 0x414243. As said in the other answer, this value is implementation dependent.
When you try to access it using '%c', the overflown part will be cut and you are only left with 0x43, which is 'C'.
To get more insight to it, read the answers to this question as well.
The conversion specifier c used in this call
printf("i=%c",i);
in fact extracts one character from the integer argument. So using this specifier you in any case can not get three characters as the output.
From the C Standard (7.21.6.1 The fprintf function)
c If no l length modifier is present, the int argument is converted to
an unsigned char, and the resulting character is written
Take into account that the internal representation of a multi-byte character constant is implementation defined. From the C Standard (6.4.4.4 Character constants)
...The value of an integer character constant containing more than one character (e.g., 'ab'), or containing a character or escape
sequence that does not map to a single-byte execution character, is
implementation-defined.
'ABC' is an integer character constant. Depending on code set (overwhelming it is ASCII), endian, int width (apparently 32 bits in OP's case), it may have the same value like below. It is implementation defined behavior.
'ABC'
0x41424300
0x434241
or others.
The "%c" directs printf() to take the int value, cast it to unsigned char and print the associated character. This is the main reason for apparent loss of information.
In OP's case, it appears that i took on the value of 0x434241.
int i='A';
printf("i=%c",i); --> 'A'
// same as
printf("i=%c",0x434241); --> 'A'
if you want i to contain 3 characters you need to init a array that contains 3 characters
char i[3];
i[0]= 'A';
i[1]= 'B';
i[2]='C';
the ' ' can contain only one char your code converts the integer i into a character or better you store in your 32 bit intiger a converted 8 bit character. But i think You want to seperate the 32 bits into 8 bit containers make a char array like char i[3]. and then you will see that
int j=i;
this will result in an error because you are unable to convert a char array into a integer.
In C, 'A' is an int constant that's guaranteed to fit into a char.
'ABC' is a multicharacter constant. It has an int type, but an implementation defined value. The behaviour on using %c to print that in printf is possibly undefined if the value cannot fit into a char.

assigning more than one character in char

Why this program gives output 'y'
#include <stdio.h>
int main(void) {
char ch='abcdefghijklmnopqrstuvwxy';
printf("%c",ch);
return 0;
}
Code at ideone
It's a multi-character literal.
An ordinary character literal that contains more than one c-char is a
multicharacter literal . A multicharacter literal has type int and
implementation-defined value.
Also from 6.4.4.4/10 in C11 specs
An integer character constant has type int. The value of an integer
character constant containing a single character that maps to a
single-byte execution character is the numerical value of the
representation of the mapped character interpreted as an integer. The
value of an integer character constant containing more than one
character (e.g., 'ab'), or containing a character or escape sequence
that does not map to a single-byte execution character, is
implementation-defined. If an integer character constant contains a
single character or escape sequence, its value is the one that results
when an object with type char whose value is that of the single
character or escape sequence is converted to type int.
So the line char ch = 'abcdefghijklmnopqrstuvwxy' on your system (assuming 4 byte int) possibly compiles to:
char ch = 0x76777879; // SOME int value (may be different, but documented in the compiler documents)
ch will be assigned 'abcdef...y' which may be equivalent to (int)0x616263646566...79 in ascii encoding and overflows an integer. This is the reason why gcc generates the following warning:
multicharlit.c: In function ‘main’: multicharlit.c:4:13: warning:
character constant too long for its type [enabled by default]
multicharlit.c:4:5: warning: overflow in implicit constant conversion
[-Woverflow]
It appears on your system, least significant 8 bits are used to assign to ch. Because your character literal is constant, this most possibly happens at compile time: (For example following happens when I compile with gcc)
$ cat multicharlit.c
#include <stdio.h>
int main(void) {
char ch='abcdefghijklmnopqrstuvwxy';
printf("%c",ch);
return 0;
}
$ gcc -O2 -fdump-tree-optimized multicharlit.c
$ cat multicharlit.c.143t.optimized
;; Function main (main) (executed once)
main ()
{
<bb 2>:
__builtin_putchar (121);
return 0;
}
Also stealing some goodness from unwind's comment
Remember that the type of a single-quoted character constant is int,
but you're assigning it to a char, so it has to be truncated to a
single character.
Type of 'a' for example is int in C. (Not to be confused with 'a' in C++ which is a char. On the other hand type of 'ab' is int in both C and C++.)
Now when you assign this int type to a char type and value is more than that can be represented by a char, then some squeezing needs to be done to fit the result into less wider type char and the actual result is implementation-defined.
If you intended to print out abcdefghijklmnopqrstuvwxy, then you should have stored it into a string variable instead of a char one (char ch[50] = char abcdefghijklmnopqrstuvwxy;).
String variables can hold more than one character, where as a char variable is for holding one character.

Please explain this result please. printf("%c", 'abcd')

#include <stdio.h>
int main()
{
printf("%c\n", 'abcd');
printf("%p\n", 'abcd');
printf("%c\n", 0x61626364);
printf("%c\n", 0x61626363);
printf("%c\n", 0x61626365);
return 0;
}
I want to ask this line : printf("%c\n", 'abcd');
In this line, the result is 'd' but, I can't understand why 'd' is come out.
I tried to look other memories. In this situation, I found other memories have all alphabets.
Please explain me why result is 'd' and why other memories have all alphabets.
Thank you.
'abcd' is a multi-character constant, its value is implementation-defined.
C11 §6.4.4.4 Character constants section 10
An integer character constant has type int. The value of an integer character constant
containing a single character that maps to a single-byte execution character is the
numerical value of the representation of the mapped character interpreted as an integer.
The value of an integer character constant containing more than one character (e.g.,
'ab'), or containing a character or escape sequence that does not map to a single-byte
execution character, is implementation-defined. If an integer character constant contains
a single character or escape sequence, its value is the one that results when an object with
type char whose value is that of the single character or escape sequence is converted to
type int.
A common implementation gives 'abcd' a value of 'a' * 256 * 256 * 256 + 'b' * 256 * 256 + 'c' * 256 + 'd' (1633837924), you can check its value in your implementation by printing it using "%d". Although legal C, it's rarely used in practice.
Your code is wrong. When you compile it with a recent GCC compiler enabling warnings with
gcc -Wall -Wextra u.c
you get
u.c: In function 'main':
u.c:5:20: warning: multi-character character constant [-Wmultichar]
printf("%c\n", 'abcd');
^
u.c:6:20: warning: multi-character character constant [-Wmultichar]
printf("%p\n", 'abcd');
^
u.c:6:5: warning: format '%p' expects argument of type 'void *', but argument 2 has type 'int' [-Wformat=]
printf("%p\n", 'abcd');
^
Technically, you are in the awful undefined behavior case (and unspecified behavior for the multi-character constants), and anything could happen with a standard compliant implementation.
I never saw any useful case for multi-character constants like 'abcd'. I believe they are useless and mostly are an historical artefact.
To explain what really happens, it is implementation specific (depends upon the compiler, the processor, the optimization flags, the ABI, the runtime environment, ....) and you need to dive into gory details (first look at the generated assembler code with gcc -fverbose-asm -S) and into your libc particular printf implementation.
As a rule of thumb, you should improve your code to get rid of every warnings your compiler is able to give you (your compiler is helpful in warning you). They are few subtle exceptions (but then you should comment your code about them).
printf("%c\n", 'abcd');
As noted already, the value of 'abcd' is implementation-defined. On your implementation, its value is 0x61626364, so it behaves the same as your third printf call. See below.
printf("%p\n", 'abcd');
As noted already, %p is used to print pointers. 'abcd' is not a pointer, so this call is simply invalid.
printf("%c\n", 0x61626364);
printf("%c\n", 0x61626363);
printf("%c\n", 0x61626365);
The specification for %c reads:
If no l length modifier is present, the int argument is converted to an unsigned char, and the resulting character is written.
Conversions of int to unsigned char are well-defined and reduce the value modulo UCHAR_MAX+1. On most implementations, this means it takes the lowest 8 bits of the number.
The lowest 8 bits of 0x61626364, 0x61626363 and 0x61626365 are 0x64, 0x63 and 0x65, which in ASCII correspond to 'd', 'c' and 'e', so ASCII implementations will print those characters.
Your code
printf("%c\n", 'abcd');
results in output
d
due to the "%c" specifying a single character. Because multiple characters were provided instead of a single character, the multi-character constant was 'converted' to a single character by taking the last character of the string.
The result of providing a string where a single character is expected is the "implementation-defined" behavior. This means different compilers can handle this differently. See stackoverflow.com/multiple-characters-in-a-character-constant.

unable to get char of 2 character long in C [duplicate]

This question already has answers here:
How to determine the result of assigning multi-character char constant to a char variable?
(5 answers)
Closed 8 years ago.
following statement in c gives no error
char p='-1';
but the following gives error:
char p='-12';
ERROR: character can be one or two characters long.
I never knew that a char in c can ever be two characters long. However printf("%c",p) gives - as output. Where can i use char in c?
In C, a character constant like 'A' does not have type char, but rather type int. This creates the possibility that, even on a system where char is only 8 bits wide (and so int is wider than char), character constant notations can exist which provide integer values wider than char.
The C standard requires implementations to support multi-character constants, but their values are implementation-defined.
Why your compiler allows only two characters is likely because the type int is only 16 bits wide. Perhaps a constant like 'AB' is encoded similarly to, say, the expression ('A' << 8 | 'B'). According to the obvious extension of this scheme, 'ABC' would then have to be ('A' << 16 | 'B' << 8 | 'C') which doesn't fit into 16 bits and calls for out-of-range shifts. Hence, the two character limit.
In the GNU C compiler, four characters can be used:
#include <stdio.h>
int main(void)
{
printf("%x\n", (unsigned) 'ABCD');
return 0;
}
int is 32 bits wide, and this program prints 41424344 which, by golly, is hexadecimal for the ASCII characters ABCD. So this feature is useful for int-wide magic constants which are readable. Instead of:
#define MAGIC 0x41424344 /* This spells ABCD; easy to spot in memory dumps */
You can do this, which is nice, but less portable:
#define MAGIC 'ABCD'
What if we use five or more characters, like 'ABCDE'? Then GCC respond similarly to how Turbo C++ responds for three or more:
test.c:5:35: warning: character constant too long for its type [enabled by default]
It so happens that the program still compiles, and its output is unchanged: the E was truncated.
There is an important difference. The old Borland compiler is rejecting the excessively-long constant as an error. Though that is probably a good idea, it is not standard-conforming; when some value is implementation-defined, the implementation's response cannot be failure, such as stopping the translation or execution of the program. Issuing a diagnostic is fine, of course.
char p='-517';
printf("%c\n", p);
Running the above code gave me output 7 and a warning: overflow in implicit constant conversion [-Woverflow]
char can not contain more than 1 byte of information
You want an array of characters, also known as a C-string
// Note, if you initialize a character array with a literal string
// there is no need for a size specifier
char c[] = "-12";
// Note this is a method of copying one character array into another.
#include <string.h>
char c[4];
strcpy(c, "-12");
You'll notice that char c[4] has an indicated size of 4. Meaning, the array can only hold 4 characters. In C, character arrays have a special property: A null terminator (char '\0') is a sentinel value that C-string functions use to recognize the end of your string. So, in reality, a character string "-12" is of size 4. '-', '1', '2', and '\0'.
You can also access individual elements of an array by passing an indice to it's operator[] function.
printf("%s\n", c);
printf("%c\n", c[0]);
Notice the c[0] call, This will access the character '-' of the string "-12".
Hope I helped.

why '\97' ascii value equals 55

Just like C code:
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
the result is 55,but I can't understand how to calculate it.
I know the Octal number or hex number follow the '\', does the 97 is hex number?
\ is a octal escape sequence but 9 is not a valid octal digit so instead of interpreting it as octal it is being interpreted as a multi-character constant a \9 and a 1 whose value is implementation defined. Without any warning flags gcc provides the following warnings by default:
warning: unknown escape sequence: '\9' [enabled by default]
warning: multi-character character constant [-Wmultichar]
warning: overflow in implicit constant conversion [-Woverflow]
The C99 draft standard in section 6.4.4.4 Character constants paragraph 10 says (emphasis mine):
An integer character constant has type int. The value of an integer character constant
containing a single character that maps to a single-byte execution character is the
numerical value of the representation of the mapped character interpreted as an integer.
The value of an integer character constant containing more than one character (e.g.,
'ab'), or containing a character or escape sequence that does not map to a single-byte
execution character, is implementation-defined.
For example gcc implementation is documented here and is as follows:
The compiler evaluates a multi-character character constant a character at a time, shifting the previous value left by the number of bits per target character, and then or-ing in the bit-pattern of the new character truncated to the width of a target character. The final bit-pattern is given type int, and is therefore signed, regardless of whether single characters are signed or not (a slight change from versions 3.1 and earlier of GCC). If there are more characters in the constant than would fit in the target int the compiler issues a warning, and the excess leading characters are ignored.
For example, 'ab' for a target with an 8-bit char would be interpreted as ‘(int) ((unsigned char) 'a' * 256 + (unsigned char) 'b')’, and '\234a' as ‘(int) ((unsigned char) '\234' * 256 + (unsigned char) 'a')’.
As far as I can tell this is being interpreted as:
char c = ((unsigned char)'\71')*256 + '7' ;
which results in 55, which is consistent with the multi-character constant implementation above although the translation of \9 to \71 is not obvious.
Edit
I realized later on what is really happening is the \ is being dropped and so \9 -> 9, so what we really have is:
c = ((unsigned char)'9')*256 + '7' ;
which seems more reasonable but still arbitrary and not clear to me why this is not a straight out error.
Update
From reading The Annotated C++ Reference Manual we find out that in Classic C and older versions of C++ when backslash followed character was not defined as an scape sequence it was equal to the numeric value of the character. ARM section 2.5.2:
This differs from the interpretation by Classic C and early versions of C++, where the value of a sequence of a blackslash followed by a character in the source character set, if not defined as an escape sequence, was equal to the numeric value of the character. For example '\q' would be equal to 'q'.
\9 is not a valid escape, so the compiler ignores it and ascii '7' is 55.
I would not depend on this behavior, it's probably undefined. But that's where the 55 came from.
edit: Shafik points out it's not undefined, it's implementation defined. See his answer for the references.
First of all, I'm going to assume your code should read this, because it matches your title.
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
\9 isn't valid, thus let's just assume the character is actually 7. 7 is ascii 55, which is the answer that was printed out.
I'm not sure what you wanted, but \97 isn't it...
\9 isn't a valid escape sequence, so it's likely falling back to a plain 9 character.
This means that it's the same thing as '97', which is undefined implementation defined (see Shafik Yaghmour's answer) behavior (2 characters can't fit into 1 character...).
To avoid things like this in the future, consider cranking up the warnings on your compiler. For example, a minimum for gcc should be -Wall -Wextra -pedantic.

Resources