Portable Test for long long Support

M

Mark Shelor

Problem: find a portable way to determine whether a compiler supports
the "long long" type of C99.

I thought I had this one solved with the following code:


#include <limits.h>


#ifdef ULONG_LONG_MAX

/* 64-bit code */

#endif


This seemed to work on most platforms until I compiled today under
Mandrake linux i586 (gcc 3.2.2). What's odd is that this compiler
supports the "long long" type, yet the 64-bit code didn't get included.

Any ideas? Is there a "standard" way to test whether a C compiler
supports the C99 types?

Mark
 
A

Arthur J. O'Dwyer

Problem: find a portable way to determine whether a compiler supports
the "long long" type of C99.

I thought I had this one solved with the following code:

#include <limits.h>

#ifdef ULONG_LONG_MAX

I believe the correct macro name is ULLONG_MAX (and the signed
equivalents would be LLONG_MAX and LLONG_MIN).
/* 64-bit code */

#endif
This seemed to work on most platforms until I compiled today under
Mandrake linux i586 (gcc 3.2.2). What's odd is that this compiler
supports the "long long" type, yet the 64-bit code didn't get included.

Any ideas? Is there a "standard" way to test whether a C compiler
supports the C99 types?

That way looks like the safest way to me. But, as another thread
pointed out recently, just because your 'gcc' supports

long long int foo;

doesn't necessarily mean that your version of 'libc' supports

printf("%lld\n", foo);

You'll need to test all the relevant library functions as well as
the core language support. And that will probably get painful.
It might be easier in some cases to simply let the guy compiling
the program set a macro through -DUSE_LONG_LONG or whatever, and
let *him* take the blame for incomplete 'long long' support. :)
I.e., skip the <limits.h> test and just write

#if USE_LONG_LONG
[...stuff...]
#else
[...stuff using 'long' only...]
#endif


My $.02,
-Arthur
 
C

Chris Torek

Problem: find a portable way to determine whether a compiler supports
the "long long" type of C99.

I thought I had this one solved with the following code:

#include <limits.h>

#ifdef ULONG_LONG_MAX
[snippage]

Actually, the C99 name for the macros are LLONG_MIN, LLONG_MAX,
and ULLONG_MAX respectively.

You may encounter systems that have (partial or complete) support
for "long long" but do not have the defines, simply because those
systems are not (yet?) C99-conformant and no effort was put into
updating the headers.

In some ways this is related to the hypothetical situation of an
otherwise C89-conformant system that fails to define __STDC__ as
1, and therefore fails to conform. :)
 
K

Keith Thompson

Mark Shelor said:
Problem: find a portable way to determine whether a compiler supports
the "long long" type of C99.

I thought I had this one solved with the following code:


#include <limits.h>


#ifdef ULONG_LONG_MAX

/* 64-bit code */

#endif


This seemed to work on most platforms until I compiled today under
Mandrake linux i586 (gcc 3.2.2). What's odd is that this compiler
supports the "long long" type, yet the 64-bit code didn't get included.

Any ideas? Is there a "standard" way to test whether a C compiler
supports the C99 types?

As others have pointed out, the relevant macros are LLONG_MAX and
ULLONG_MAX. But since "long long" appeared as an extension before it
was blessed by the C99 standard, there may be implementations that
provide long long but don't have LLONG_MAX and ULLONG_MAX.

You might consider testing during configuration rather than during
compilation. For example, you might write a small C program that
declares a long long variable and appends the line

#define HAVE_LONG_LONG

to one of your application header files. Try to compile and run the
program. If long long is supported, it will run and append the line;
if it's not, it will fail to compile, and HAVE_LONG_LONG won't be
defined for your application.

BTW, are you really looking for type long long or for a 64-bit type?
Type long long is guaranteed to be at least 64 bits, but there could
be implementations that don't define long long, but that have 64-bit
longs. Consider using uint64_t or uint_least64_t from <stdint.h> If
your implementation doesn't have <stdint.h>, Doug Gwyn has written a
reasonably portable C90-compatible implementation of it; see
<http://www.lysator.liu.se/c/q8/index.html>.
 
M

Mark Shelor

Keith said:
As others have pointed out, the relevant macros are LLONG_MAX and
ULLONG_MAX. But since "long long" appeared as an extension before it
was blessed by the C99 standard, there may be implementations that
provide long long but don't have LLONG_MAX and ULLONG_MAX.

BTW, are you really looking for type long long or for a 64-bit type?
Type long long is guaranteed to be at least 64 bits, but there could
be implementations that don't define long long, but that have 64-bit
longs. Consider using uint64_t or uint_least64_t from <stdint.h> If
your implementation doesn't have <stdint.h>, Doug Gwyn has written a
reasonably portable C90-compatible implementation of it; see
<http://www.lysator.liu.se/c/q8/index.html>.


Thanks Keith, Arthur, Chris for the helpful replies.

Yes, I did try using ULLONG_MAX earlier in the day, but had no luck
there either. Oddly, when I grep'd on ULONG_LONG_MAX in the
/usr/include subdirectories, the response I got was

$ grep ULONG_LONG_MAX `find /usr/include -print`
/usr/include/limits.h:# define ULLONG_MAX ULONG_LONG_MAX

However, since this #define was nested within other #ifdef's that
apparently get excluded during the compile, the token ULLONG_MAX didn't
show up as being defined.

If I remove my original conditional compilation directive, and simply go
ahead and include the 64-bit code (with unsigned long long's),
everything compiles and runs just fine. So, this has me scratching my
head a bit.

I'm using this #ifdef in a package I wrote for CPAN. It's a C
implementation (wrapped in a Perl module) of NIST's Secure Hash
Algorithms (SHA-1/256/384/512). Basically, the latter two (384/512) use
64-bit operations, so I note in my documentation that run-time code for
them won't exist if one's native compiler lacks support for long long's.
However, the package will still compile and run just fine.

Since this package gets downloaded, compiled, and installed by lots of
people with C compilers of unknown capability, I've written the code to
be as vanilla and portable as possible. What I DON'T want to have
happen is for a person's compile to crash if his compiler doesn't happen
to support long long's. It's acceptable in those circumstances for the
package to omit support for SHA-384 and SHA-512, which fortunately
aren't really crucial in the near-term anyway.

Yet another oddity is the fact that the 64-bit code gets included when I
compile it under the automake facility that's provided as part of the
Perl packaging utility (h2xs). However, when I compile it as a
standalone C program with a simple test driver, the 64-bit code is
missing. I don't have the patience to wade through the myriad compiler
options and define's used by h2xs to figure out what's going on! :)

Regards, Mark
 
A

Arthur J. O'Dwyer

I'm using this #ifdef in a package I wrote for CPAN. It's a C
implementation (wrapped in a Perl module) of NIST's Secure Hash
Algorithms (SHA-1/256/384/512). Basically, the latter two (384/512) use
64-bit operations, so I note in my documentation that run-time code for
them won't exist if one's native compiler lacks support for long long's.
However, the package will still compile and run just fine.

Since this package gets downloaded, compiled, and installed by lots of
people with C compilers of unknown capability, I've written the code to
be as vanilla and portable as possible.

If you wanted to be really nice, you could write (or better, Google)
a couple of routines for 64-bit multiplication, rotation, or whatever
using pairs of 32-bit variables, and then write a 32-bit version of
your code that way, for people whose machines don't support 64-bit
stuff on a hardware level but who still want to use your module.

#ifdef HAVE_LONG_LONG
unsigned long long x = 0x238776a8f887ea60;
x <<= 6;
x += 17;
#else
unsigned int xh = 0x238776a8;
unsigned int xl = 0xf887ea60;
xh <<= 6;
xh |= xl >> (32-6);
xl <<= 6;
ull_add(&xh, &xl, 0, 17);
#endif


HTH,
-Arthur
 

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
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top