Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #19843 > unrolled thread

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

Started byJohn Reye <jononanon@googlemail.com>
First post2012-04-23 12:38 -0700
Last post2012-05-07 21:40 -0700
Articles 13 — 8 participants

Back to article view | Back to comp.lang.c


Contents

  Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. John Reye <jononanon@googlemail.com> - 2012-04-23 12:38 -0700
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. Thomas Richter <thor@math.tu-berlin.de> - 2012-04-23 22:08 +0200
      Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. James Kuyper <jameskuyper@verizon.net> - 2012-04-23 16:45 -0400
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. John Reye <jononanon@googlemail.com> - 2012-04-23 13:28 -0700
      Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. James Kuyper <jameskuyper@verizon.net> - 2012-04-23 17:01 -0400
      Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-05-04 00:30 -0700
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. Ben Pfaff <blp@cs.stanford.edu> - 2012-04-23 13:36 -0700
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. James Kuyper <jameskuyper@verizon.net> - 2012-04-23 17:11 -0400
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. John Gordon <gordon@panix.com> - 2012-04-23 22:03 +0000
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. John Reye <jononanon@googlemail.com> - 2012-05-03 15:35 -0700
      Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. Jens Gustedt <jens.gustedt@loria.fr> - 2012-05-04 09:00 +0200
        Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. James Kuyper <jameskuyper@verizon.net> - 2012-05-04 07:54 -0400
    Re: Generates integer literal of the largest value a variable can hold. Macro takes only variable-name. Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 21:40 -0700

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

FromJohn Reye <jononanon@googlemail.com>
Date2012-04-23 12:38 -0700
SubjectGenerates integer literal of the largest value a variable can hold. Macro takes only variable-name.
Message-ID<3b194163-c8e2-4250-864a-d3f0a1324677@f5g2000vby.googlegroups.com>
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.

[toc] | [next] | [standalone]


#19845

FromThomas Richter <thor@math.tu-berlin.de>
Date2012-04-23 22:08 +0200
Message-ID<jn4csb$2mn$1@news.belwue.de>
In reply to#19843
On 23.04.2012 21:38, John Reye wrote:
> 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

[toc] | [prev] | [next] | [standalone]


#19848

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-04-23 16:45 -0400
Message-ID<4F95BF7F.10500@verizon.net>
In reply to#19845
On 04/23/2012 04:08 PM, Thomas Richter wrote:
> On 23.04.2012 21:38, John Reye wrote:
>> 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

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.

[toc] | [prev] | [next] | [standalone]


#19846

FromJohn Reye <jononanon@googlemail.com>
Date2012-04-23 13:28 -0700
Message-ID<858f1f2a-5c55-439b-b83d-3d4d6efcb150@f5g2000vby.googlegroups.com>
In reply to#19843
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!

[toc] | [prev] | [next] | [standalone]


#19849

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-04-23 17:01 -0400
Message-ID<4F95C335.8090509@verizon.net>
In reply to#19846
On 04/23/2012 04:28 PM, John Reye wrote:
> 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
[u]int_least8_t, [unsigned] short as [u]int_least16_t, [unsigned] int as
[u]int_fast16_t, and [unsigned] long as [u]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.

[toc] | [prev] | [next] | [standalone]


#20376

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2012-05-04 00:30 -0700
Message-ID<3328648.45.1336116639044.JavaMail.geo-discussion-forums@ynje14>
In reply to#19846
בתאריך יום שני, 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.

-- 
Basic Algorithms: now also available as an iBook
http://www.malcolmmclean.site11.com/www

[toc] | [prev] | [next] | [standalone]


#19847

FromBen Pfaff <blp@cs.stanford.edu>
Date2012-04-23 13:36 -0700
Message-ID<874nsaw5h3.fsf@blp.benpfaff.org>
In reply to#19843
John Reye <jononanon@googlemail.com> writes:

> 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 */

[toc] | [prev] | [next] | [standalone]


#19851

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-04-23 17:11 -0400
Message-ID<4F95C589.1080208@verizon.net>
In reply to#19843
On 04/23/2012 03:38 PM, John Reye wrote:
> 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.

[toc] | [prev] | [next] | [standalone]


#19854

FromJohn Gordon <gordon@panix.com>
Date2012-04-23 22:03 +0000
Message-ID<jn4jjp$p8q$1@reader1.panix.com>
In reply to#19843
In <number-20120423234415@ram.dialup.fu-berlin.de> ram@zedat.fu-berlin.de (Stefan Ram) writes:

>   The largest value a single bit can hold is not limited.

That's stretching the meaning of the word "hold", isn't it?

-- 
John Gordon                   A is for Amy, who fell down the stairs
gordon@panix.com              B is for Basil, assaulted by bears
                                -- Edward Gorey, "The Gashlycrumb Tinies"

[toc] | [prev] | [next] | [standalone]


#20362

FromJohn Reye <jononanon@googlemail.com>
Date2012-05-03 15:35 -0700
Message-ID<a047e22e-f4ec-49bb-b6ce-5cb08b616c07@cl4g2000vbb.googlegroups.com>
In reply to#19843
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.

[toc] | [prev] | [next] | [standalone]


#20374

FromJens Gustedt <jens.gustedt@loria.fr>
Date2012-05-04 09:00 +0200
Message-ID<4FA37EA0.50003@loria.fr>
In reply to#20362
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

[toc] | [prev] | [next] | [standalone]


#20385

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-05-04 07:54 -0400
Message-ID<jo0g10$fjj$1@dont-email.me>
In reply to#20374
On 05/04/2012 03:00 AM, Jens Gustedt wrote:
> 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

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.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#20489

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-07 21:40 -0700
Message-ID<kfn1umvxp3s.fsf@x-alumni2.alumni.caltech.edu>
In reply to#19843
John Reye <jononanon@googlemail.com> writes:

> 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.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web