How do I get the 1 that overflowed?
To do it afterwards in a portable way (not forgetting that unsigned int might only be 16 bits):
    uint32_t a = 0Xffffffff;
    uint32_t b = 0xffffffff;
    uint32_t c_low = a + b;
    uint32_t c_high;
    if(c_low >= a) {
        c_high = 0;
    } else {
        c_high = 1;
    }
To do it beforehand in a portable way (without branches):
    uint32_t a = 0Xffffffff;
    uint32_t b = 0xffffffff;
    uint32_t c_low;
    uint32_t c_high;
    c_high = (a&b) >> 31;
    c_low = (a ^ (c_high<<31)) + b;
  How can I do the same for multiplication?
Multiplication doesn't have a carry, it has an "upper half". Specifically; if you multiply an unsigned integer that has N bits with an unsigned integer that has M bits then the result will have N+M bits; and if both numbers had the same size then the result will be twice as big.
Sadly C doesn't support "result type is larger than source/s types", so you need to "pre-promote" the source types, like:
    uint32_t a = 0Xffffffff;
    uint32_t b = 0xffffffff;
    uint64_t temp = (uint64_t)a * (uint64_t)b;
    uint32_t c_low = temp;
    uint32_t c_high = temp >> 32;
Of course if the compiler doesn't support a larger type then you have to split it into smaller pieces, like:
    uint32_t a = 0Xffffffff;
    uint32_t b = 0xffffffff;
    uint32_t a_low = a & 0xFFFF;
    uint32_t a_high = a >> 16;
    uint32_t b_low = a & 0xFFFF;
    uint32_t b_high = b >> 16;
    uint32_t temp_0 = a_low * b_low;
    uint32_t temp_16a = a_high * b_low;
    uint32_t temp_16b = a_low * b_high;
    uint32_t temp_32 = a_high * b_high;
    uint32_t c_low = temp_0 + (temp16a << 16) + (temp16b << 16);
    uint32_t c_high = (temp16a >> 16) + (temp16b >> 16) + temp_32;
  How do bigint libraries manage this?
Mainly; they use inline assembly language because most CPUs support instructions to work on bigger integers efficiently and/or because you can access the carry flag directly. For example; for 80x86; the CPU has adc/sbb, shld/shrd, mul (with double width result)/div (with double width numerator); plus maybe extensions (adcx and adox).
In 32-bit 80x86 assembly language, the addition might look like:
    xor edx,0
    add eax,ebx      ;c_low = a + b
    adc edx,0        ;c_high = carry
..and the multiplication might look like:
    mul ebx          ;edx:eax = a * b
     
    
if(UINT_MAX - a < b) then handle_it()unsigned long long intis a standard C type that must have at least 64 bits, so, for your 32-bit example, the product can be computed as(unsigned long long int) a * b, after which the low and high 32 bits can be extracted by shifting and masking.