Question
Consider this program:
#include <stdio.h>
int main(void)
{
printf("sizeof(char) = %zu\n", sizeof(char));
printf("sizeof('a') = %zu\n", sizeof('a'));
}
When compiled as C, a typical result is:
sizeof(char) = 1
sizeof('a') = 4
When compiled as C++, a typical result is:
sizeof(char) = 1
sizeof('a') = 1
Why does sizeof('a') differ between C and C++? What is the size of a character in each language if char is one byte in both?
Short Answer
The difference is not about the size of the char type. It is about the type of the character literal 'a'. In C, an ordinary character literal has type int; in C++, it has type char. Therefore, sizeof('a') is usually sizeof(int) in C and exactly sizeof(char) in C++.
Concept
A character literal is a value written between single quotes, such as 'a', '?', or '\n'.
It is important not to confuse these two expressions:
char letter = 'a'; // `char` is a type used for the variable
sizeof('a'); // `'a'` is a character literal with language-specific type
In C, an ordinary character literal such as 'a' has type int.
/* C */
sizeof('a') == sizeof(int)
In C++, an ordinary character literal such as 'a' has type char.
// C++
sizeof('a') == sizeof(char)
That is why the same source text can produce different results when compiled as C and as C++.
sizeof(char) is always 1 in both languages. However, 1 means one C/C++ byte, not necessarily eight bits. The number of bits in a byte is available through CHAR_BIT from <limits.h> in C or <climits> in C++ and is at least 8.
On many modern systems:
sizeof(char)is1sizeof(int)is4
So C commonly prints 4 for sizeof('a'), while C++ prints 1. The C result is not guaranteed to be 4; it is whatever sizeof(int) is on that implementation.
Mental Model
Think of 'a' as a label on a package, not as the package itself.
- In C, the label
'a'is placed in anint-sized package. - In C++, the label
'a'is placed in achar-sized package.
The written text is identical, but each language assigns it a different type. sizeof measures the package type chosen by the language, not the visual number of characters between the quotes.
Syntax and Examples
Use sizeof to inspect the size of a type or expression.
sizeof(char) /* size of the char type */
sizeof(int) /* size of the int type */
sizeof('a') /* size of the type of the literal 'a' */
C example
#include <stdio.h>
int main(void)
{
printf("char: %zu\n", sizeof(char));
printf("int: %zu\n", sizeof(int));
printf("'a': %zu\n", sizeof('a'));
}
In C, 'a' has type int, so the final two sizes match:
char: 1
int: 4
'a': 4
C++ example
#include <cstdio>
int main()
{
std::printf("char: %zu\n", sizeof(char));
std::printf("int: %zu\n", sizeof(int));
std::printf("'a': %zu\n", sizeof('a'));
}
In C++, 'a' has type char, so the first and final sizes match:
char: 1
int: 4
'a': 1
A portable way to state the key rule is:
/* C: sizeof('a') == sizeof(int) */
/* C++: sizeof('a') == sizeof(char) */
Step by Step Execution
Trace this C program:
#include <stdio.h>
int main(void)
{
int code = 'A';
printf("%d\n", code);
printf("%zu\n", sizeof('A'));
}
- The compiler reads
'A'. - In C, the literal
'A'has typeint. - Its numeric value corresponds to the execution character set's code for
A(commonly 65, but do not assume ASCII in fully portable C). - The assignment to
int codeneeds no conversion because the literal is already anint. sizeof('A')measures the literal's type, so it producessizeof(int).
Now consider the C++ version:
#include <cstdio>
int main()
{
int code = 'A';
std::printf("%d\n", code);
std::printf("%zu\n", sizeof('A'));
}
- In C++,
'A'has typechar. - Assigning it to
int codeconverts thecharvalue toint. sizeof('A')still measures the original literal type,char.- Therefore, it produces
1.
The assignment can look the same in both languages, but the literal begins with a different type.
Real World Use Cases
This difference matters when code is shared between C and C++ or when code relies on exact types.
- Cross-language libraries: A header or macro used by both C and C++ should not assume that
'x'has the same type in both languages. - Generic macros: In C, macros using
_Genericcan select different behavior for'a'and acharvariable because the literal is anint. - Overloaded C++ functions: In C++, overload resolution can choose a
charoverload for'a'. - Binary and text protocols: Developers often store byte values in
unsigned charbuffers. They should explicitly convert when a specific byte type is required. - Portability checks:
sizeof(char)andCHAR_BITare the correct tools for learning about the platform's byte representation;sizeof('a')is not a measurement of character storage.
Real Codebase Usage
Developers usually treat character literals as values, then choose an explicit type when storage or API contracts matter.
Store a byte explicitly
unsigned char marker = (unsigned char)'M';
This is useful for byte buffers, file formats, and network data. The cast makes the intended destination type clear.
Validate a character range
int is_ascii_digit(char ch)
{
return ch >= '0' && ch <= '9';
}
The literals may have different types in C and C++, but the comparisons work because the operands are converted as required by each language.
Use int for character input results in C
int ch = getchar();
if (ch == EOF) {
/* No more input or an input error. */
} else if (ch == 'q') {
/* Handle q. */
}
getchar() returns int, not char, so it can represent every unsigned char value plus the special EOF value. This is one historical reason int is common in C character-processing APIs.
C++ overloads can observe the type
#include <cstdio>
void print_kind(char) { std::puts("char"); }
void print_kind(int) { std::puts("int"); }
int main()
{
print_kind('a'); // Calls print_kind(char) in C++
}
C has no function overloading, but this example shows why C++ literal types can affect real API calls.
Common Mistakes
Mistake: assuming 'a' is always a char
/* Incorrect assumption in C */
sizeof('a') == sizeof(char)
In C, 'a' is an int. Use a char variable when you need the size of the char type:
char ch = 'a';
printf("%zu\n", sizeof(ch));
Mistake: treating a byte as always 8 bits
/* Not fully portable */
if (sizeof(char) == 1) {
/* Assume char has 8 bits */
}
sizeof(char) is always 1, so this check says nothing about its bit width. Use CHAR_BIT:
#include <limits.h>
printf("bits in a byte: %d\n", CHAR_BIT);
Mistake: using char to store getchar() directly
char ch = getchar(); /* Can lose the EOF value */
Use int until after checking for EOF:
int ch = getchar();
if (ch != EOF) {
/* Safe to process ch as a character value. */
}
Mistake: expecting a particular sizeof(int)
/* Not portable */
_Static_assert(sizeof(int) == 4, "int must be four bytes");
Many systems use a 4-byte int, but the language does not require it. In C, sizeof('a') is sizeof(int), so it is not guaranteed to be 4 either.
Mistake: confusing character and string literals
'a' /* one character literal */
"a" /* a string literal containing 'a' and a terminating '\0' */
A string literal has array type and is a different concept from a character literal.
Comparisons
| Expression or type | In C | In C++ | Key point |
|---|---|---|---|
char | A character type; sizeof(char) == 1 | A character type; sizeof(char) == 1 | Same size rule in both languages. |
'a' | Type int | Type char | This causes the sizeof difference. |
sizeof('a') | sizeof(int) | sizeof(char) | Often 4 in C and 1 in C++, but only the relationship is guaranteed. |
"a" | Character array containing a and \0 | Character array containing a and \0 | A string literal, not a character literal. |
L'a' | Wide character literal, typically wchar_t-related | Wide character literal of type wchar_t | Different from an ordinary literal. |
char versus int
char is intended for individual character and byte-sized values. int is a general integer type. In C, ordinary character literals use int even though they represent character codes. In C++, ordinary character literals use char, which more directly matches how programmers commonly think of a single character.
Cheat Sheet
-
sizeof(char)is always1in both C and C++. -
A C/C++ byte has
CHAR_BITbits, whereCHAR_BIT >= 8. -
In C, an ordinary literal such as
'a'has typeint. -
In C++, an ordinary literal such as
'a'has typechar. -
Therefore:
/* C */ sizeof('a') == sizeof(int)// C++ sizeof('a') == sizeof(char) -
sizeof('a')is not guaranteed to be 4 in C; it depends onsizeof(int). -
'a'is a character literal;"a"is a string literal. -
Store
getchar()results inintso thatEOFcan be detected. -
Use
CHAR_BIT, notsizeof(char), to find the number of bits in a byte.
FAQ
Why is sizeof(char) always 1?
The languages define a byte as the amount of storage occupied by a char. Therefore, sizeof(char) must be 1 by definition.
Does sizeof(char) == 1 mean a char has 8 bits?
No. It means char occupies one language byte. Use CHAR_BIT to get the number of bits in that byte. It is at least 8.
Why are C character literals int values?
This is a historical C language design choice. It also fits C character APIs such as getchar(), which use int so they can represent both character values and EOF.
Is sizeof('a') always 4 in C?
No. In C it equals sizeof(int). Four is common, but the C standard does not require that size.
Is sizeof('a') always 1 in C++?
For an ordinary character literal such as 'a', yes: its type is char, and sizeof(char) is always 1.
Does 'a' always have the ASCII value 97?
No. C and C++ use an implementation's execution character set. ASCII is common, but portable code should not assume a specific numeric value unless its environment requires one.
What is the difference between 'a' and "a"?
'a' is one character literal. "a" is a string literal: an array containing a followed by a null terminator.
Mini Project
Description
Build a small diagnostic program that reports the sizes of character-related types and demonstrates the different type of an ordinary character literal in C and C++. This is useful when learning portability and when maintaining code that can be compiled in either language.
Goal
Print platform character information and identify whether 'A' behaves as an int literal (C) or a char literal (C++).
Requirements
Requirement 1
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.