Question

C vs C++ Character Literals: Why sizeof('a') Differs

ccpptypescharsizeof

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) is 1
  • sizeof(int) is 4

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 an int-sized package.
  • In C++, the label 'a' is placed in a char-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.

Take Quiz

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'));
}
  1. The compiler reads 'A'.
  2. In C, the literal 'A' has type int.
  3. Its numeric value corresponds to the execution character set's code for A (commonly 65, but do not assume ASCII in fully portable C).
  4. The assignment to int code needs no conversion because the literal is already an int.
  5. sizeof('A') measures the literal's type, so it produces sizeof(int).

Now consider the C++ version:

#include <cstdio>

int main()
{
    int code = 'A';
    std::printf("%d\n", code);
    std::printf("%zu\n", sizeof('A'));
}
  1. In C++, 'A' has type char.
  2. Assigning it to int code converts the char value to int.
  3. sizeof('A') still measures the original literal type, char.
  4. 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 _Generic can select different behavior for 'a' and a char variable because the literal is an int.
  • Overloaded C++ functions: In C++, overload resolution can choose a char overload for 'a'.
  • Binary and text protocols: Developers often store byte values in unsigned char buffers. They should explicitly convert when a specific byte type is required.
  • Portability checks: sizeof(char) and CHAR_BIT are the correct tools for learning about the platform's byte representation; sizeof('a') is not a measurement of character storage.
Take Quiz

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 typeIn CIn C++Key point
charA character type; sizeof(char) == 1A character type; sizeof(char) == 1Same size rule in both languages.
'a'Type intType charThis 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 \0Character array containing a and \0A string literal, not a character literal.
L'a'Wide character literal, typically wchar_t-relatedWide character literal of type wchar_tDifferent 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.

Take Quiz

Cheat Sheet

  • sizeof(char) is always 1 in both C and C++.

  • A C/C++ byte has CHAR_BIT bits, where CHAR_BIT >= 8.

  • In C, an ordinary literal such as 'a' has type int.

  • In C++, an ordinary literal such as 'a' has type char.

  • Therefore:

    /* C */
    sizeof('a') == sizeof(int)
    
    // C++
    sizeof('a') == sizeof(char)
    
  • sizeof('a') is not guaranteed to be 4 in C; it depends on sizeof(int).

  • 'a' is a character literal; "a" is a string literal.

  • Store getchar() results in int so that EOF can be detected.

  • Use CHAR_BIT, not sizeof(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.

Take Quiz

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

Take Quiz

Keep learning

Related questions

View more