c1 = block[i1]; c2 = block[i2];
if (c1 != c2) return (c1 > c2);
i1++; i2++;
becomes mov cl, byte ptr [rdx + rcx]
cmp byte ptr [rdx + rax], cl
jne .LBB0_6
lea eax, [rdi + 2]
lea ecx, [rsi + 2]
if the indices are unsigned, but mov al, byte ptr [rcx + rdx + 1]
cmp byte ptr [rdi + rdx + 1], al
jne .LBB1_6
if the indices are signed, that is the compiler just removes the indices and traverses the block directly (starting at the input offsets).That's because in C (and C++) overflow is UB, so the compiler can assume it doesn't happen. Clang is apparently unable to make such a determination or work around it for unsigned, so for every increment of the indices it actually goes and computes the indices to fetch the items from the array.
Incidentally, GCC does not care and generates the exact same (rather different) code for both signednesses.