Assigning unsigned to signed types and vice versa

Let's explore the interactions between signed and unsigned variables in C with complete examples, including the binary representations in the outputs. These examples will illustrate the effects of sign and zero extension, especially in corner cases.

1. Unsigned to Signed Assignment

Example:

#include <stdio.h>

int main() {
    unsigned int u = 4294967295; // Maximum unsigned int value
    int s = u; // Assigning unsigned to signed

    printf("Unsigned: %u, Binary: %x\n", u, u);
    printf("Signed: %d, Binary: %x\n", s, s);

    return 0;
}

Expected Output:

Unsigned: 4294967295, Binary: ffffffff
Signed: -1, Binary: ffffffff

Explanation: The maximum unsigned int, represented in binary as all 1s, becomes -1 in a signed int due to two's complement representation.

2. Signed to Unsigned Assignment

Example:

#include <stdio.h>

int main() {
    int s = -1; // Negative signed int
    unsigned int u = s; // Assigning signed to unsigned

    printf("Signed: %d, Binary: %x\n", s, s);
    printf("Unsigned: %u, Binary: %x\n", u, u);

    return 0;
}

Expected Output:

Signed: -1, Binary: ffffffff
Unsigned: 4294967295, Binary: ffffffff

Explanation: -1 in signed int, with binary representation as all 1s, is interpreted as the maximum unsigned int value when assigned to an unsigned variable.

3. Small Unsigned to Larger Signed Type

Example:

#include <stdio.h>

int main() {
    unsigned char uc = 255; // Maximum unsigned char value
    int s = uc; // Assigning small unsigned to larger signed

    printf("Unsigned char: %u, Binary: %x\n", uc, uc);
    printf("Signed int: %d, Binary: %x\n", s, s);

    return 0;
}

Expected Output:

Unsigned char: 255, Binary: ff
Signed int: 255, Binary: 000000ff

Explanation: The unsigned char value 255 (0xff) is zero-extended to fit into a larger signed int, maintaining its value.

4. Small Signed to Larger Unsigned Type

Example:

#include <stdio.h>

int main() {
    signed char sc = -1; // Negative signed char
    unsigned int u = sc; // Assigning small signed to larger unsigned

    printf("Signed char: %d, Binary: %x\n", sc, sc);
    printf("Unsigned int: %u, Binary: %x\n", u, u);

    return 0;
}

Expected Output:

Signed char: -1, Binary: ffffffff
Unsigned int: 4294967295, Binary: ffffffff

Explanation: The signed char -1 (0xff when cast to unsigned for printing) is sign-extended to an unsigned int, becoming the maximum value of unsigned int.

5. Larger Unsigned to Smaller Signed Type

Example:

#include <stdio.h>

int main() {
    unsigned int u = 4294967295; // Large unsigned int
    signed char sc = u; // Assigning larger unsigned to smaller signed

    printf("Unsigned int: %u, Binary: %x\n", u, u);
    printf("Signed char: %d, Binary: %x\n", sc, sc);

    return 0;
}

Expected Output:

Unsigned int: 4294967295, Binary: ffffffff
Signed char: -1, Binary: ff

Explanation: When the large unsigned int (0xffffffff) is assigned to a smaller signed char, it's truncated to 0xff, which is -1 in signed representation.

These examples show how the binary representations of signed and unsigned integers interact during assignments in C, highlighting the effects of sign and zero extension, and potential issues like truncation.