Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C checking for signed number representation

The following way of checking for the signed number representation checks for twos complement correctly on my machine, but I dont have ones complement or signed magnitude machines to check it. Would the code work properly and more importantly, is it portable?

File: platform.h

#ifndef PLATFORM_H
#define PLATFORM_H
#include <limits.h>

static
const union {
    signed char sc;
    unsigned char uc;
} plat_4xvYw = {.sc = -1};

#define IS_TWOS_COMPL (plat_4xvYw.uc == UCHAR_MAX)
#define IS_ONES_COMPL (plat_4xvYw.uc == UCHAR_MAX - 1)
#define IS_SIGNED_MAG (plat_4xvYw.uc == (1U << (CHAR_BIT - 1)) + 1U)

#endif

File: a.c

#include <inttypes.h>
#include <limits.h>
#include "platform.h"
#include <assert.h>

int
main (void) {

    assert (IS_TWOS_COMPL);
    if (IS_TWOS_COMPL) {

        printf ("twos complement\n");
    } else if (IS_ONES_COMPL) {

        printf ("ones complement\n");
    } else if (IS_SIGNED_MAG) {

        printf ("signed magnitude\n");
    }
    return 0;
}
like image 994
tyty Avatar asked Nov 09 '11 12:11

tyty


1 Answers

I think you're better off just masking the bits of a negative int:

if ((-1 & 0x1) == 0) {
    // -1 ends in "0" => 1s' complement
} else if ((-1 & 0x2) == 0) {
    // -1 ends in "01" => sign-magnitude
} else {
    // -1 ends in "11" => two's complement
}

Strictly speaking, this doesn't tell you the same thing as your code, since there's no guarantee that int and signed char use the same meaning of the sign bit. But (a) seriously? and (b) this works for types int and larger, for smaller types it's trickier. unsigned char is guaranteed to have no padding bits, but signed char is not. So I think it's legal to have (for example) CHAR_BIT == 9, UCHAR_MAX = 511, CHAR_MAX = 127, and signed char has 1 padding bit. Then your code could fail: the sign bit in the stored signed value isn't necessarily where you expect it to be, and the value of the padding bit could be either 0 or 1.

In a lot of cases you could just use int8_t in the program instead of signed char. It's guaranteed to be 2's complement if it exists, so might save you from caring about the representation of signed char. If it doesn't exist, the program won't compile, which is kind of what you're asserting anyway. You'd get a false negative from platforms which are 2's complement, but don't have an 8-bit char and therefore do not provide int8_t. This may or may not bother you...

like image 150
Steve Jessop Avatar answered Sep 20 '22 06:09

Steve Jessop