Skip to content

49 Intermediate The Hundred

The Character That Went Negative

a pixel so bright it came out the other side

#include <iostream>

int main() {
    char sample = 200;   // one 8-bit greyscale pixel — nearly white

    std::cout << "value:  " << static_cast<int>(sample) << "\n";
    std::cout << "bright: " << (sample > 100 ? "yes" : "no") << "\n";
    std::cout << "dimmed: " << sample / 2 << "\n";
}

Run it. How bright is that pixel?

Answer
value:  -56
bright: no
dimmed: -28

The near-white pixel is darker than black.

Why

Plain char is a third character type, distinct from both signed char and unsigned char, and the standard lets every implementation choose which of the two it behaves like. On x86-64 — Linux, macOS, Windows alike — it is signed, so it spans −128…127 and the 200 wraps to −56; every comparison and every division downstream then works on that. Rebuild the same file with -funsigned-char and it prints 200, yes, 100 instead — exactly the default on ARM and PowerPC Linux. -Wall -Wextra say nothing about the initialization; -Wpedantic does: overflow in conversion from 'int' to 'char' changes value from '200'.

The practical bite lives in <cctype>: std::toupper, std::isalpha and friends require an argument representable as unsigned char or EOF, so passing a negative char — any byte above 127, which includes every non-ASCII UTF-8 byte — is undefined behavior. glibc keeps 128 spare table entries below zero, so on GCC/x86-64 it quietly returns the right answer and the bug hides; another library is free to read straight off the front of its table.

The fix

Use unsigned char (or std::uint8_t) for raw bytes, and cast at every ctype call site:

unsigned char sample = 200;                         // value: 200, bright: yes, dimmed: 100
std::toupper(static_cast<unsigned char>(sample));   // defined for every byte

Takeaway: char is for characters, not for byte values — the moment a byte can exceed 127, spell the type unsigned char.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry