Often char is signed and 8 bits (<note>but it can be more, while sizeof(char)==1 by definition, leading to bytes of more than 8 bits</note>) thus char ofChar = 255; reads as initialize a char with the int value 255, which requires a conversion (see below), and after initialization ofChar is actually -1.
NB: On initialization standard type conversion occurs:
If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is implementation-defined(until C++20)the unique value of the destination type equal to the source value modulo 2n
where n is the number of bits used to represent the destination type(since C++20) (note that this is different from signed integer arithmetic overflow, which is undefined).
Then adding an int constant 1 to your variables, they are submitted to integral promotion meaning that ofInt si converted to an int with value 255 and (ofInt + 1) returns the int 256.
see https://en.cppreference.com/w/cpp/language/operator_arithmetic.html and https://en.cppreference.com/w/cpp/language/usual_arithmetic_conversions.html.
The same happen to ofChar and (ofChar + 1) is actually -1 + 1 thus 0.
This yields the behavior you're observing.
Side note, with appropriate compiler options, you may have an hint about what's happening: https://godbolt.org/z/d8s73YGvx
<source>: In function 'int main()':
<source>:10:19: warning: overflow in conversion from 'int' to 'char' changes value from '255' to '-1' [-Woverflow]
10 | char ofChar = 255;
How to check the signedness of char:
#include <cstdint>
#include <format>
#include <iostream>
#include <type_traits>
int main() {
std::cout << std::format("is uint8_t unsigned? {}\n",
std::is_unsigned_v<std::uint8_t>);
std::cout << std::format("is char unsigned? {}\n",
std::is_unsigned_v<char>);
}
LIVE
charis signed by default, then(-1 + 1) == 0is true.charis implementation-defined.charis signed. Signed number overflows are undefined behavior. You cannot tell for sure what the result will be.