Maximum value for typedef'd type

  • Thread starter Fred L. Kleinschmidt
  • Start date
F

Fred L. Kleinschmidt

I need to know the largets value representable in a variable. However, I
do not know the variable's true type - only that it is some kind of int.
It may be any of the following:
#typedef Newtype short;
#typedef Newtype unsigned short;
#typedef Newtype int;
#typedef Newtype unsigned int;
#typedef Newtype long;
....etc.

The actual typedef used depends on the platform; this definition is made
in a third-party header over which I have no control.

Here is my code that appears to work on the platforms I am using. Have I
missed anything here? Any gotchas?

Newtype GetMaximum Newtype(void)
{
static Newtype x = ~0; /* Fill with 1's */
/*
* If x<0, then Newtype was a signed entity, so we need to negate
it.
* Note the compiler may complain if Newtype is unsigned.
*/
return ( (x < 0) ? -x : x );
}
 
B

Bertrand Mollinier Toublet

Fred said:
I need to know the largets value representable in a variable. However, I
do not know the variable's true type - only that it is some kind of int.
It may be any of the following:
#typedef Newtype short;
#typedef Newtype unsigned short;
#typedef Newtype int;
#typedef Newtype unsigned int;
#typedef Newtype long;
...etc.

The actual typedef used depends on the platform; this definition is made
in a third-party header over which I have no control.

Here is my code that appears to work on the platforms I am using. Have I
missed anything here? Any gotchas?

Newtype GetMaximum Newtype(void)
{
static Newtype x = ~0; /* Fill with 1's */
/*
* If x<0, then Newtype was a signed entity, so we need to negate
it.
* Note the compiler may complain if Newtype is unsigned.
*/
return ( (x < 0) ? -x : x );
}
Yes, there are gotchas including, if I am not mistaken, undefined
behaviour in some cases, as evidenced by the thread entitled "Many happy
returns" that has been running this week.
 
J

Joona I Palaste

Fred L. Kleinschmidt said:
I need to know the largets value representable in a variable. However, I
do not know the variable's true type - only that it is some kind of int.
It may be any of the following:
#typedef Newtype short;
#typedef Newtype unsigned short;
#typedef Newtype int;
#typedef Newtype unsigned int;
#typedef Newtype long;
...etc.

This is the entirely wrong syntax for typedef. # marks a preprocessor
directive, while typedef is a feature of the actual C language.
Presumably you mean:
typedef short Newtype;
typedef unsigned short Newtype;
and so on.

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"The obvious mathematical breakthrough would be development of an easy way to
factor large prime numbers."
- Bill Gates
 
K

Kevin Bracey

In message <[email protected]>
"Fred L. Kleinschmidt said:
I need to know the largets value representable in a variable. However, I
do not know the variable's true type - only that it is some kind of int.

Here is my code that appears to work on the platforms I am using. Have I
missed anything here? Any gotchas?

Newtype GetMaximum Newtype(void)
{
static Newtype x = ~0; /* Fill with 1's */

To reliably fill it with 1's, that has to be "~(Newtype) 0".
/*
* If x<0, then Newtype was a signed entity, so we need to negate
it.
* Note the compiler may complain if Newtype is unsigned.
*/
return ( (x < 0) ? -x : x );
}

That assumes sign-and-magnitude representation for signed integers, as far as
I can see. That's not common, but it may match your platform. For 2's
complement you end up returning 1, and for 1's complement you either return 0
or invoke undefined behaviour.

A better start would be

static Newtype x = -1;

That will set x to -1 if it is signed, and to NEWTYPE_MAX if it is unsigned,
on any system. Thus we can next say

if (x > 0) return x;

Signed types are much harder to probe without invoking undefined behaviour or
relying on outside knowledge. Let's try though. C guarantees one of 3
representations for signed integers - sign-and-magnitude, 2's complement or
1's complement.

I think you can safely determine which representation is in use safely by
saying

x = ~(Newtype) 1;

x now has all its value bits set except the "1" bit, and the sign bit is set.
What exactly that means depends on the representation.

if (x == -1)
/* representation is 1's complement */;
else if (x == -2)
/* representation is 2's complement */;
else
/* representation is sign-and-magnitude */;

Note that this test (indeed probably the whole function) can be evaluated at
compile time.

Sign-and-magnitude is straightforward. For that one we just

return (-x) + 1;

For the other two, we've got a problem. We need to set all the value bits,
and clear the sign bit, but how to achieve this without invoking undefined
behaviour? Integer overflow is undefined, left-shift of positive values
outside the range is undefined, and whether you can have the sign bit set and
all value bits clear is implementation-defined.

I can't see any way of doing it without making some sort of assumption. The
safest may be to assume that left shift overflow throws away the excess bits
or moves them through the sign bit, and do something like:

x = 0xFF; // avoids trap representations at end of shift
while ((x << 1) > x)
x <<= 1;
return x | (x >> 8);

If there is a nice, portable answer to this, I can't see it :(
 
D

Dan Pop

In said:
I need to know the largets value representable in a variable. However, I
do not know the variable's true type - only that it is some kind of int.
It may be any of the following:
#typedef Newtype short;
#typedef Newtype unsigned short;
#typedef Newtype int;
#typedef Newtype unsigned int;
#typedef Newtype long;
...etc.

You may want to learn C before worrying about such issues. typedef is
not a preprocessor directive and it has a completely different syntax than
the #define directive.
The actual typedef used depends on the platform; this definition is made
in a third-party header over which I have no control.

Here is my code that appears to work on the platforms I am using. Have I
missed anything here? Any gotchas?

Newtype GetMaximum Newtype(void)

This is definitely not a valid function definition.
{
static Newtype x = ~0; /* Fill with 1's */
/*
* If x<0, then Newtype was a signed entity, so we need to negate
it.
* Note the compiler may complain if Newtype is unsigned.
*/
return ( (x < 0) ? -x : x );
}

This is all wrong. If Newtype is signed, the most likely result is 1.

The trick is to use the widest unsigned type (unsigned long in C89) for
this purpose:

unsigned long max = -1;
while ((Newtype)max < 0 || (Newtype)max != max) max >>= 1;
return max;

The code exploits the fact that the maximum value is one less than a
power of two. It is theoretically unsafe on C99 implementations, where
(Newtype)max is allowed to raise an implementation-defined signal if
the value of max cannot be represented by Newtype.

Dan
 
F

Fred L. Kleinschmidt

Joona said:
This is the entirely wrong syntax for typedef. # marks a preprocessor
directive, while typedef is a feature of the actual C language.
Presumably you mean:
typedef short Newtype;
typedef unsigned short Newtype;
and so on.

Yeah, I did a cut/paste from a print that uses "#" as a linestart
indicator, and forgot to remove it to show the real source text.
 
F

Fred L. Kleinschmidt

Kevin said:
In message <[email protected]>


To reliably fill it with 1's, that has to be "~(Newtype) 0".


That assumes sign-and-magnitude representation for signed integers, as far as
I can see. That's not common, but it may match your platform. For 2's
complement you end up returning 1, and for 1's complement you either return 0
or invoke undefined behaviour.

A better start would be

static Newtype x = -1;

That will set x to -1 if it is signed, and to NEWTYPE_MAX if it is unsigned,
on any system. Thus we can next say

if (x > 0) return x;

Signed types are much harder to probe without invoking undefined behaviour or
relying on outside knowledge. Let's try though. C guarantees one of 3
representations for signed integers - sign-and-magnitude, 2's complement or
1's complement.

I think you can safely determine which representation is in use safely by
saying

x = ~(Newtype) 1;

x now has all its value bits set except the "1" bit, and the sign bit is set.
What exactly that means depends on the representation.

if (x == -1)
/* representation is 1's complement */;
else if (x == -2)
/* representation is 2's complement */;
else
/* representation is sign-and-magnitude */;

Note that this test (indeed probably the whole function) can be evaluated at
compile time.

Sign-and-magnitude is straightforward. For that one we just

return (-x) + 1;

For the other two, we've got a problem. We need to set all the value bits,
and clear the sign bit, but how to achieve this without invoking undefined
behaviour? Integer overflow is undefined, left-shift of positive values
outside the range is undefined, and whether you can have the sign bit set and
all value bits clear is implementation-defined.

I can't see any way of doing it without making some sort of assumption. The
safest may be to assume that left shift overflow throws away the excess bits
or moves them through the sign bit, and do something like:

x = 0xFF; // avoids trap representations at end of shift
while ((x << 1) > x)
x <<= 1;
return x | (x >> 8);

If there is a nice, portable answer to this, I can't see it :(

--
Kevin Bracey, Principal Software Engineer
Tematic Ltd Tel: +44 (0) 1223 503464
182-190 Newmarket Road Fax: +44 (0) 1223 503458
Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/

I know that NewType must be one of the six
(unsigned/signed)(short/int/long).
Thus here is what I am now trying:

Newtype GetMaximum Newtype(void)
{
static Newtype x = -1; /* negative if signed, MAXVAL if unsigned */
static int len = sizeof(Newtype);

if ( x > 0 ) {
return x; /* Newtype is an unsigned type */
}
/* Newtype is a signed type */
if (len == sizeof(short)) {
return (Newtype)USHRT_MAX;
}
else if (len == sizeof(long)) {
return (Newtype)ULONG_MAX;
}
return (Newtype)INT_MAX; /* as a default, if not short or long */
}
 
J

Jirka Klaue

Fred L. Kleinschmidt wrote:
....
I know that NewType must be one of the six
(unsigned/signed)(short/int/long).
Thus here is what I am now trying:

Newtype GetMaximum Newtype(void)
{
static Newtype x = -1; /* negative if signed, MAXVAL if unsigned */
static int len = sizeof(Newtype);

if ( x > 0 ) {
return x; /* Newtype is an unsigned type */
}
/* Newtype is a signed type */

OK, so far.
if (len == sizeof(short)) {
return (Newtype)USHRT_MAX;

USHRT_MAX? For a signed variable?

Furthermore, the size of a type is not related to the range representable
by this type. Have a look at Dan Pop's reply for a possible solution.

Jirka
 
J

Joona I Palaste

Yeah, I did a cut/paste from a print that uses "#" as a linestart
indicator, and forgot to remove it to show the real source text.

Looks like the print uses really strange syntax then, because the
syntax of "typedef" is that the new type (Newtype in this case) must
appear *after* the actual type, not before it.
In other words: the print reads:
typedef Newtype short;
when it should read:
typedef short Newtype;
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,206
Latest member
Zenden

Latest Threads

Top