Using static cast would probably result in something like this:
// This does not prevent a possible type overflow
const char char_max = -1;
int i = 48;
char c = (i & char_max);
To prevent possible type overflow you could do this:
const char char_max = (char)(((unsigned char) char(-1)) / 2);
int i = 128;
char c = (i & char_max); // Would always result in positive signed values.
Where reinterpret_cast would probably just directly convert to char, without any cast safety.
-> Never use reinterpret_cast if you can also use static_cast.
If you're casting between classes, static_cast will also ensure, that the two types are matching (the object is a derivate of the cast type).
If your object a polymorphic type and you don't know which one it is, you should use dynamic_cast which will perform a type check at runtime and return nullptr if the types do not match.
IF you need const_cast you most likely did something wrong and should think about possible alternatives to fix const correctness in your code.
char c = i;and not worry about which cast is which. Of course, if you do that you'll run afoul of the "cast everywhere" folks who insist that compiler warnings be turned into errors and then fixed wherever they occur.