Generates integer literal of the largest value a variable can hold.Macro takes only variable-name.

J

John Reye

Assume you have a variable called
var
of unknown type. (Or that the type can be changed).

How can one construct a literal, to be the largest value that this
variable can hold, without information about the variables type?





#include <stdio.h>
#define MAX_VALUE_OF_VAR(var) (how should this macro look like, please
use helper macros if necessary)

int main()
{
signed char var = 0; // only change this line (to other types)
do {
++var;
printf("%lld, ", (long long int) var);
} while (var != MAX_VALUE_OF_VAR(var));
return 0;
}

In the above, I currently expect the output to be 1, 2, 3, ..., 127

If above is changed:
signed short var = 0;
.... then I would like the output to be
1, 2, 3, ..., 32767

If above is changed:
signed int var = 0;
.... and recompile, then I would like the output to be
1, 2, 3, ..., 2147483647

etc.


Is it possible to construct a macro MAX_VALUE_OF_VAR that handles both
signed and unsigned?
I've tried and am having a lot of trouble with integer promotions and
the MSB for negative numbers.

Is this possible at all.
Thanks for pointers.
 
T

Thomas Richter

Assume you have a variable called
var
of unknown type. (Or that the type can be changed).

How can one construct a literal, to be the largest value that this
variable can hold, without information about the variables type?

Not in C in a completely portable way. If you are contained to standard
architectures with binary representation of data, you could check

a) whether the 1/2 in this variable equals zero or not. If not, it not
an integer type, otherwise, HUGE_VAL should be the largest possible value,
b) if (-1) casted to the type is positive, it is unsigned, and the
result is the largest possible value,
c) otherwise, on *many standard* systems, you may try to use 1 <<
((sizeof(type) << 3)-1) for signed types.

But as said, this is not portable. In C++, type traits would offer the
full functionality you need, and even without using the preprocessor.

So long,
Thomas
 
J

John Reye

Ahh that C's right?

Sortof slightly "statically typed".
Then then they throw in integer promotions to ease writing code in
some cases, but causes novice programmer's bugs and kills the type-
system in other cases.

Writing portable C-code that works across different word-sizes must be
a real horror!
 
B

Ben Pfaff

John Reye said:
Assume you have a variable called
var
of unknown type. (Or that the type can be changed).

How can one construct a literal, to be the largest value that this
variable can hold, without information about the variables type?

The following works for integer types on "ordinary" sytems.

/*
* Copyright (c) 2008, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef TYPE_PROPS_H
#define TYPE_PROPS_H 1

#include <limits.h>

#define TYPE_IS_INTEGER(TYPE) ((TYPE) 1.5 == (TYPE) 1)
#define TYPE_IS_SIGNED(TYPE) ((TYPE) 1 > (TYPE) -1)
#define TYPE_VALUE_BITS(TYPE) (sizeof(TYPE) * CHAR_BIT - TYPE_IS_SIGNED(TYPE))
#define TYPE_MINIMUM(TYPE) (TYPE_IS_SIGNED(TYPE) \
? ~(TYPE)0 << TYPE_VALUE_BITS(TYPE) \
: 0)
#define TYPE_MAXIMUM(TYPE) (TYPE_IS_SIGNED(TYPE) \
? ~(~(TYPE)0 << TYPE_VALUE_BITS(TYPE)) \
: (TYPE)-1)

/* Number of decimal digits required to format an integer of the given TYPE.
* Includes space for a sign, if TYPE is signed, but not for a null
* terminator.
*
* The value is an overestimate. */
#define INT_STRLEN(TYPE) (TYPE_IS_SIGNED(TYPE) + TYPE_VALUE_BITS(TYPE) / 3 + 1)

#endif /* type-props.h */
 
J

James Kuyper

Not in C in a completely portable way. If you are contained to standard
architectures with binary representation of data, you could check

The error density in the next sentence is truly amazing. Some people
consider sentences like this one to be the sign of a troll. I'll
withhold judgement for now on that issue.
a) whether the 1/2 in this variable equals zero or not. ...

Setting any arithmetic type to 1/2 should produce a result of 0 for all
arithmetic types. I think you mean 0.5.
... If not, it not
an integer type, ...

This is both simpler and has better grammar: "if so, it is an integer
type". This would also fix the error in the rest of the sentence:
... otherwise, HUGE_VAL should be the largest possible value,

I think you got confused by having two many "not"s. As written, assuming
that you meant 0.5 rather than 1/2, and were thinking of 'double' as the
only floating point type, that's exactly backwards.

But that still doesn't work; HUGE_VAL is for doubles, HUGE_VALF and
HUGE_VALL are for float and long double, respectively. If you knew which
one of those three options was relevant, that would violate one of the
specified conditions: no information about the type.

The HUGE_VAL* macros are special positive values used by the standard
library for indicating error conditions; their values are otherwise not
constrained. It's entirely possible for HUGE_VAL to be 1 (though that
would be a very bad idea).
b) if (-1) casted to the type is positive, it is unsigned, and the
result is the largest possible value,

Again, if he knew the type to cast it to, that would violate the
specified condition: "no information about the type".
c) otherwise, on *many standard* systems, you may try to use 1 <<
((sizeof(type) << 3)-1) for signed types.

Why use "<<3" rather than "*CHAR_BIT"? It's not portable, but it's more
portable than "<<3".
You're missing the final -1 in your expression.
 
J

James Kuyper

Ahh that C's right?

Sortof slightly "statically typed".
Then then they throw in integer promotions to ease writing code in
some cases, but causes novice programmer's bugs and kills the type-
system in other cases.

Writing portable C-code that works across different word-sizes must be
a real horror!

Not really. If you need exact or minimum sizes, using the size-named
types from <stdint.h>. If you need C90 capability (or just want to use
shorter type names), think of [un]signed char as essentially the same as
int_least8_t, [unsigned] short as int_least16_t, [unsigned] int as
int_fast16_t, and [unsigned] long as int_least32_t. Except, of
course, that they're not required to have 2's complement type, and
(except for unsigned char) are allowed to have padding bits.

I won't claim it's trivial to deal with all of these issues, but it's
not a horror. Careful use of the corresponding MIN and MAX macros from
<stdint.h> or <limits.h> respectively, will deal with most of the
relevant problems.

If you want a language that guarantees more about it's fundamental types
than C does, try Java; but keep in mind the efficiency penalties of
using a type guaranteed to be exactly 16 bits on a 32-bit machine (or
vice versa). If that inefficiency doesn't bother you, and the
corresponding uncertainty about whether 'int' has 16 or 32 bytes does,
then C is definitely NOT the language for you.
 
J

James Kuyper

Assume you have a variable called
var
of unknown type. (Or that the type can be changed).

How can one construct a literal, to be the largest value that this
variable can hold, without information about the variables type?

#include <stdio.h>
#define MAX_VALUE_OF_VAR(var) (how should this macro look like, please
use helper macros if necessary)

int main()
{
signed char var = 0; // only change this line (to other types)
do {
++var;
printf("%lld, ", (long long int) var);
} while (var != MAX_VALUE_OF_VAR(var));
return 0;
}

In the above, I currently expect the output to be 1, 2, 3, ..., 127

If above is changed:
signed short var = 0;
... then I would like the output to be
1, 2, 3, ..., 32767

If above is changed:
signed int var = 0;
... and recompile, then I would like the output to be
1, 2, 3, ..., 2147483647

Do you have enough time to read that output? Do you have enough paper
an toner to print it out?
Is it possible to construct a macro MAX_VALUE_OF_VAR that handles both
signed and unsigned?
I've tried and am having a lot of trouble with integer promotions and
the MSB for negative numbers.

Is this possible at all.

Not in general.

For unsigned types, assigning a value of -1 to the variable will set it
to the maximum value of it's type. Would it be acceptable for the macro
to change the variable's value? It wouldn't work in your example code -
would your intended use for this macro allow a re-write to avoid that
problem? Assigning a value of -1 to a variable is a perfectly safe thing
to do for all arithmetic types, and testing whether the result is
greater than 0 is a safe and reliable way of testing for unsignedness.

If you're willing to make non-portable but very often correct
assumptions, like 2's complement and no padding bits or trap
representations, then

((long long)pow(2.0,CHAR_BIT*sizeof(var) - 1)-1)

works for the signed types. If you need portability to systems where
those assumptions don't apply, you're out of luck.

The "no type information" approach seems rather odd - it's not something
that comes up very often in idiomatically written C - you almost always
know the type of anything you work with, except when using typedefs. It
sound almost as if you were trying to write a C++ template in C. You
need to approach problems differently when using C than when using C++.
If you try to force C to work like C++, you're going to frustrate
yourself and mystify those who work on your code later, trying to
implement poor substitutes for genericity in C.
 
S

Stefan Ram

John Reye said:
How can one construct a literal, to be the largest value that this
variable can hold, without information about the variables type?

The largest value a single bit can hold is not limited.
It just depends on the code used. For example, I can use this code:

bit
state meaning
0 the number 0
1 the number 100^100^100^100^100^100^100^100^100^100^100^100^100^100

For large numbers, see:

http://www.scottaaronson.com/writings/bignumbers.html
http://mathoverflow.net/questions/34710/succinctly-naming-big-numbers-zfc-versus-busy-beaver
http://jeremykun.wordpress.com/2012/02/08/busy-beavers-and-the-quest-for-big-numbers/
http://en.wikipedia.org/wiki/Busy_beaver
http://www.strangehorizons.com/2001/20010402/biggest_numbers.shtml
http://mrob.com/pub/math/largenum-5.html

. With C, one can use the literal »1«:

{ number c;
init( &c, 1 );
print( c ); }

will print

100^100^100^100^100^100^100^100^100^100^100^100^100^100

, given an appropriate definition for »number«, »init«, and »print«
(exercise).
 
S

Stefan Ram

John Gordon said:
That's stretching the meaning of the word "hold", isn't it?

What's the largest number a double can hold in your preferred C implementation?

What's the second largest number it can hold (the next representable number smaller
than the first)?

In which sense does a double object »hold« these two values that does not apply
to the bit I described?
 
J

John Reye

Here's a nice hack for... getting the max value for any unsigned type:
from "unsigned char" to "unsigned long long":

#include <stdio.h>
#include <limits.h>

#define GET_TYPE_INT_OR_LARGER_0(var) (var & 0)

#define GET_SHIFT_CHAR_BIT2(var) ((sizeof(var) >= sizeof(int)) ? 0 :
(CHAR_BIT * (sizeof(int)-sizeof(var))))

/* only unsigned */
#define GET_MAX_UNSIGNED_RVALUE(var) ((GET_TYPE_INT_OR_LARGER_0(var)
-1U) >> GET_SHIFT_CHAR_BIT2(var))


int main(void)
{
typedef unsigned long long my_ull;

my_ull var2;
printf("%llx\n", GET_MAX_UNSIGNED_RVALUE(var2));

unsigned i;
printf("%x\n", GET_MAX_UNSIGNED_RVALUE(i));

unsigned short s;
printf("%x\n", GET_MAX_UNSIGNED_RVALUE(s));

unsigned char c;
printf("%x\n", GET_MAX_UNSIGNED_RVALUE(c));

return 0;
}

What do you think?

Does the macro GET_MAX_UNSIGNED_RVALUE() really create a literal?
(i.e. something that can be used in #if ... preprocessing)
Or does it depend on the compiler?

Thanks.
 
J

Jens Gustedt

Am 05/04/2012 12:35 AM, schrieb John Reye:
Here's a nice hack for... getting the max value for any unsigned type:
from "unsigned char" to "unsigned long long":

#include <stdio.h>
#include <limits.h>

#define GET_TYPE_INT_OR_LARGER_0(var) (var & 0)

#define GET_SHIFT_CHAR_BIT2(var) ((sizeof(var) >= sizeof(int)) ? 0 :
(CHAR_BIT * (sizeof(int)-sizeof(var))))

What do you think?

Does the macro GET_MAX_UNSIGNED_RVALUE() really create a literal?
(i.e. something that can be used in #if ... preprocessing)
Or does it depend on the compiler?

no

- IIRC ternary expressions are not allowed in the preprocessor
- sizeof is not evaluated in the preprocessor

Jens
 
M

Malcolm McLean

בת×ריך ×™×•× ×©× ×™,23 ב×פריל 2012 21:28:21 UTC+1, מ×ת John Reye:
Writing portable C-code that works across different word-sizes must be
a real horror!
Mostly integers count things. That usually means things in memory.

Even a char integer, if you think about it, is ultimately going to be used as an index into a table of glyphs.

So basically you need an integer that can index the largest array you have in memory.
 
J

James Kuyper

Am 05/04/2012 12:35 AM, schrieb John Reye:

no

- IIRC ternary expressions are not allowed in the preprocessor

The relevant restrictions are implied by the fact that the thing
following a #if is described by the grammar as a constant-expression.
"Constant expressions shall not contain assignment, increment,
decrement, function-call, or comma operators, except when they are
contained within a subexpression that is not evaluated." (6.6p3)
The ternary operator ?: is not one of the prohibited ones.
- sizeof is not evaluated in the preprocessor

More precisely, during evaluation of a #if expression, the only
identifiers that have any special meaning are macros, and "defined".
Otherwise, "all remaining identifiers (including those lexically
identical to keywords) are replaced with the pp-number 0" (6.10.1p4) As
a result, sizeof(int) gets converted into 0(0), which is a syntax error.
 
T

Tim Rentsch

John Reye said:
Assume you have a variable called
var
of unknown type. (Or that the type can be changed).

How can one construct a literal, to be the largest value that this
variable can hold, without information about the variables type?
[snip example]

In C11, all standard numeric types can be handled
using _Generic. Details left to the reader.
 

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

No members online now.

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top