ok, the actual reason for this inconsistent behavior is the underlying promoting of char and unsigned. I'd like to explain this more specificcally.
first, when compaire with a int and an unsigned int variable, their types do not matter because no matter what types they are, their have the same binary-representation in memory, that is what == operator cares.
Whereas when == applies to a char and an unsigned char varialbes, they will firstly expand to the corresponding 32-bit integer type, and how they got expaneded is the key of the inconsistency. Since ca is a char, it will be extended with the sign-bit (via MOVSX) while uca will be extended only with padding 0 (via MOVZX). Thus, they now have inconstent binary-representation.
The assembly code tells this truth.
int b1 = ia == uia;
000613E5 mov eax,dword ptr [ia]
000613E8 xor ecx,ecx
000613EA cmp eax,dword ptr [uia]
000613ED sete cl
000613F0 mov dword ptr [b1],ecx
int b2 = ca == uca;
000613F3 movsx eax,byte ptr [ca]
000613F7 movzx ecx,byte ptr [uca]
000613FB xor edx,edx
000613FD cmp eax,ecx
000613FF sete dl
00061402 mov dword ptr [b2],edx