How to uniformly detect an integer’s sign bit acro

2019-07-20 20:17发布

问题:

How to detect an int sign-ness in C?

This question is mostly of historical machines. What I am asking how to distinguish if an integer is 0 or -0. In 1's complement and sign/magnitude int encoding, both a 0 (or +0) and -0 are possible.


The simple sign bit test is to compare against 0.

int x;
printf("sign bit is %s\n", (x < 0) ? "set" : "not set");

But this fails in 1's complement and sign magnitude when x is -0.


1st Candidate approach: Mask test.
As C defines that an int must have a sign bit regardless of integer encoding, the following should work.

int x;
int SignBitMask = tbd;
printf("sign bit is %s\n", (x & SignBitMask) ? "set" : "not set");

The question becomes how to determine the value of SignBitMask in C?
SignBitMask = INT_MAX + 1 seems like a starting point.


2nd Candidate approach: create function and check bit patterns:

int IsSignBitSet(int x) {
  if (x > 0) return 0;
  if (x < 0) return 1;
  int zp = 0;
  if (memcmp(&x, &zp, sizeof x) == 0) return 0;
  int zn = -0;  // Is this even the way to form a -0?
  if (memcmp(&x, &zn, sizeof x) == 0) return 1;
  // If we get here, now what?
  return ?;
}

I'm thinking there is no portable uniform solution - maybe because the need no longer exists.

Why: I have wondered how various signed zeros were detected and printed.

Note: I have purposely avoided the "C" tag here and thought I'd try just the "History" tag first.


[Edit] Answer

Combining info of 3 answers and C11dr 6.2.6.2 "Integer types" (for int, a single sign bit must exist, the positive sign bit is 0, the negative sign bit is 1), a solution (that appears independent of 1's complement, 2's complement and sign/magnitude integer encoding) is

int IsSignBitSet_Best(int x) {
  // return 1 if x is less than 0 _or_ x is arithmetically 0 with some bit set.
  return (x < 0) || ((x == 0) && (* ((unsigned int*) &x) ));
}

The direct mask approach is simplest, but have not come up with a highly portable mask definition

int IsSignBitSet_Simple(int x) {
  static unsigned SignBitMask = 0x80;  // Or some other platform dependent mask
  return ((unsigned)x & SignBitMask) != 0;
}

回答1:

To find negative 0's just check for a zero with any bit at all set.

int testForNegative0(int x) { 
   return (x==0 && *((unsigned int*)&x)); 
}

Or to answer the question in the title:

int hasSignBitSet(int x) { 
   return (x<0) || testForNegative0(x);
}

This works for the 3 encodings you mention, it may not work for even more esoteric ones.



回答2:

Not sure exactly what you are asking. If you asking 'How do we determine if a machine is ones-complement, twos-complement, or sign-magnitude?' you can use:

if (1 & -1) {
    if (3 & -1 == 1)
        printf("sign magnitude\n");
    else
        printf("twos complement\n");
} else
    printf("ones complement\n");


回答3:

Your question is a bit confusing. Do you know the encoding ahead of time? If not, what you are is asking is impossible, as the mappings are different for different encodings. For example, the byte 1111111, has a "sign" of 0 in one's complement but a sign of -1 in two's complement. So how can there be a universal way to check if they are defined differently?

EDIT: You might be able to cheat:

int sign(int x)
{
    if (x > 0) return 1;
    if (x > -1) return 0;
    return -1;
}