Currently there are quite a few places in ROS src where 64-bit integral constants are either hard-coded to be GNU C only (?), or almost worse littered with conditional compilation.
Neither is satisfactory. 1 is making it impossible to compile using e.g. an MS compiler, and 2 makes the code so ugly that... Well, you understand.
So, in the interest of fixing this once and for all, the only option is to name a macro to handle these compiler specifics in one place, and then use that macro when defining 64-bit integral constants. The question is then, what to name it? The macro will be defined something like (omitting unsigned here):
#if defined __GNUC__ #define ZZZ(X) X##LL #elif defined _MSC_VER #define ZZZ(X) X##i64 #else #error Unknown compiler for 64-bit integral constant suffix #endif
Serious suggestions that have surfaced so far are:
DEFINE_INT64 MAKE_INT64
If suggesting something else, keep in mind that - while short might be beautiful (and fast to type), using short macros is likely to sooner or later create conflicts. - leading underscore followed by capital character or another underscore is not legal for C++. - It's to make it clear that it's a 64-bit int defined, why suggestions mentioning LL or i64, as in compiler-specific extensions/implementation details, are likely not to help or be accepted since that's exactly what we want to get away from.
Please comment.
/Mike
Hi,
So, in the interest of fixing this once and for all, the only option is to name a macro to handle these compiler specifics in one place, and then use that macro when defining 64-bit integral constants. The question is then, what to name it? The macro will be defined something like (omitting unsigned here):
I already used the following defines: (in winefile and explorer)
#ifdef _MSC_VER #define LONGLONGARG _T("I64") #else #define LONGLONGARG _T("L") #endif
#if defined __GNUC__ #define ZZZ(X) X##LL #elif defined _MSC_VER #define ZZZ(X) X##i64 #else #error Unknown compiler for 64-bit integral constant suffix #endif
Serious suggestions that have surfaced so far are:
DEFINE_INT64 MAKE_INT64
May be we can combine this ideas to a new proposal:
#ifdef __GNUC__ #define FMT_INT64 _T("L") #elif defined(_MSC_VER) #define FMT_INT64 _T("I64") #else #error Unknown compiler for 64-bit integral constant suffix #endif
"FMT" stands for "format string", I think this is a bit clearer than "DEFINE" or "MAKE".
This are some usage examples:
printf("%" FMT_INT64 "d", index); /* format 64 bit decimal integer */
sprintf(buffer, "%" FMT_INT64 "x", index); /* format 64 bit hex number, lower case */
sprintf(buffer, "%" FMT_INT64 "X", index); /* format 64 bit hex number, upper case */
_stprintf(buffer, TEXT("%") FMT_INT64 TEXT("X"), index); /* compatible both to UNICODE and ANSI builds */
Regards,
Martin
-----Original Message----- From: ros-dev-bounces@reactos.com [mailto:ros-dev-bounces@reactos.com] On Behalf Of Martin Fuchs Sent: 9. oktober 2004 17:32 To: ReactOS Development List Subject: [ros-dev] Re: Compiler-independence for 64-bit integral constants
Hi,
"FMT" stands for "format string", I think this is a bit clearer than "DEFINE" or "MAKE".
There is really no good reason not to spell it out (eg. name it FORMAT_INT64 instead).
Casper
Martin Fuchs wrote:
I already used the following defines: (in winefile and explorer)
#ifdef _MSC_VER #define LONGLONGARG _T("I64") #else #define LONGLONGARG _T("L") #endif
I think you misunderstood me. I wasn't talking about printf-ish format string specifiers, I was talking about integral literals. Where some code currently is littered with:
#if defined __GNUC__ a = 1LL; #elif defined _MSC_VER a = 1i64; #else #error unknown compiler for 64-bit integral literal #endif
to have it somewhat compiler independent, I was aiming for a single:
a = ZZZ(1);
The sprinkled conditional compilation approach is not only butt-ugly but also a maintenance nightmare, especially if there comes along a compiler using neither i64 nor LL suffix for 64-bit integral literals.
Your example does however nicely display an example of what I didn't want to see - exposing compiler specific extentions/implementation details.
Staying in the realm of C89, which we must do if any MS compilers are to be able to translate the code (since the word from MS is "we don't care about C99, and will not bother with it"), "long long" and variations thereof is a compiler specific extension to C to store a 64-bit integer as much as __int64 is.
What I would prefer is to find a macro name that isn't so long that people wildly objects to it, while at the same time make the casual reader/maintainer of the code immediately understand it's a 64-bit integer being defined without having to know specific implementation details between 2..n compilers.
Another thing to perhaps consider/look into is - what will happen when a single "long" is 64 bits (on a 64-bit CPU)? Will then "long long" be 128 bits? If so, any names containing "long long" or any variations thereof will then obviously be wrong if what's intended in the code is specifically a 64-bit value.
Your example did however bring up the next logical question, even if somewhat superceeded by the fact msvcrt.dll printf format specification by design and necessity handles the "%i64d"-style format specifications.
For code intended to run on not-ReactOS too, or with a runtime library not compatible with MS, macros such as yours can be useful. In the realm of ReactOS I however don't see this as a problem, and even if it is I think its time would be better placed as a follow-up discussion once a macro name to define 64-bit integral literals has been decided upon.
/Mike
Am Samstag, 9. Oktober 2004 18:31 schrieb Mike Nordell:
Another thing to perhaps consider/look into is - what will happen when a single "long" is 64 bits (on a 64-bit CPU)? Will then "long long" be 128 bits? If so, any names containing "long long" or any variations thereof will then obviously be wrong if what's intended in the code is specifically a 64-bit value.
afaik the garantees are: char <= short <= int <= long <= long long and sizeof(char)==1 (thus the other types can only be n chars wide)
it might be better to actually use/define [u]intX_t somewhere and stick to those for code that depends on those ranges.
patrick mauritz
How about avoiding the compiler suffix altogether and only cast the constants to a (platform independent) typedef, something like this:
#ifdef __GNUC__ typedef long long INT64; #elif defined _MSC_VER typedef __int64 INT64; #else #error Please define the INT64 typedef according to your platform #endif
and then use something like
a = (INT64)0x1;
Or we could hide the cast behind a macro such as
#define ZZZ(x) ((INT64)(x))
(I have no idea what to put instead of ZZZ MAKE_INT64 or DEFINE_INT64).
I see several advantages to this scheme:
1) It can be used both for constants and other expressions
2) It does not care about literal suffixes (e.g. whether the ll suffix means that the constant has a size of 64 bit or 128 bits). All we have to do is to define the INT64 typedef appropriately. I doubt that the compiler will generate a different code between
x = 0ll;
and
x = (long long)0;
What do you think?
Emil
Kohn Emil Dan wrote:
How about avoiding the compiler suffix altogether and only cast the constants to a (platform independent) typedef, something like this:
#ifdef __GNUC__ typedef long long INT64; #elif defined _MSC_VER typedef __int64 INT64; #else #error Please define the INT64 typedef according to your platform #endif
I can forsee one possible problem with your suggestion... I don't think the following would give the desired results:
(INT64)0x100000000
I can forsee one possible problem with your suggestion... I don't think the following would give the desired results:
(INT64)0x100000000
Compilers *do* support that, it's just not standard. GCC issues a warning about it, but it does encode it as a 64 bit "long long" constant. M$VC-- issues no warning, yet it does emit an "__int64" constant.
Perhaps in this matter you should just add to the makefile to tell GCC to ignore that particular warning? Then the only differences become typedefs and *printf (which isn't used by ReactOS anyway, being replaced with custom versions). No special wrapping macros all over the place, except for casts, I suppose, in some instances. These compilers assume (rightly so) that 0x100000000 is a 64-bit constant.
Really, I think all constant integers should be internally represented as the largest possible integer type. Then leave the compiler to bitch only when an implicit cast occurs on an out-of-range value. That's how it is now when working with chars, because constants are implied ints. The times when the difference matters are very small. Other than the meaning of the expression "0x80000000 >> 1", I can't think of any cases where the difference matters.
I personally would say C should standardize char=1 short=2 int=4 long=8 and maybe long long=16 and intptr=void *. Never going to happen though.
Melissa
$ gcc test.c -o test.exe test.c: In function `main': test.c:7: warning: integer constant is too large for "long" type $ ./test FACEC0DEDEADBEEF
C:\test>cl test.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
test.c Microsoft (R) Incremental Linker Version 7.10.3077 Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe test.obj
C:\test>test FACEC0DEDEADBEEF
#ifdef __GNUC__ #define FMT_INT64 _T("L") #elif defined(_MSC_VER) #define FMT_INT64 _T("I64") #else #error Unknown compiler for 64-bit integral constant suffix #endif
"FMT" stands for "format string", I think this is a bit clearer than "DEFINE" or "MAKE".
This are some usage examples:
printf("%" FMT_INT64 "d", index); /* format 64 bit decimal integer */
sprintf(buffer, "%" FMT_INT64 "x", index); /* format 64 bit hex number, lower case */
sprintf(buffer, "%" FMT_INT64 "X", index); /* format 64 bit hex number, upper case */
These don't work when compiling for a unicode build. It's relatively common to deal with mixed strings (e.g. smtp/pop/imap/http server/client programs should typically deal with files using unicode for paths, but the protocol specifies ASCII strings). I would plump for FMT_INT64A/FMT_INT64W/FMT_INT64 to take care of this.
Hi,
--- Mike Nordell tamlin@algonet.se wrote:
Currently there are quite a few places in ROS src where 64-bit integral constants are either hard-coded to be GNU C only (?), or almost worse littered with conditional compilation.
Now that this thread has died down I just wanted to say that I dont really care how we do it as long as its not a pain to maintain. Right now we are only about a hours worth of maintaince away from having ntosknrl and friends building on MS_VC again(if this issue is fixed).
Thanks Steven
__________________________________ Do you Yahoo!? Y! Messenger - Communicate in real time. Download now. http://messenger.yahoo.com