Skip to main content
gamedev.net
🔒 Locked

Variable size...

Started by Wyrframe Jun 15, 2002 at 3:50 PM 21 replies 2.1k views
Original Post
Wyrframe
Wyrframe
I want to declare variables of exact sizes... An int is always the size of a single register on the CPU you compile on. But I want to declare a signed integer that will always be 32 bits in size. How do I that? How do I do the same to create a 16-bit unsigned integer? I once saw something like this... int myVar:24; ... which was supposed to create a 24-bit signed integer. But I''ve yet to come across a compiler that doesn''t call syntax errors on that. Please help me out?
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
Arild Fines
Arild Fines
VC++.NET(and 6.0, I assume) accept extensions like __int32, __int16 and __int64. Other compilers will have equivalent extensions. I suggest you wrap this with a typedef and an #if/#endif block.

--AnkhSVN - A Visual Studio .NET Addin for the Subversion version control system.[Project site] [IRC channel] [Blog]
felonius
felonius
The syntax you suggest comes from bitfields. For instance:

struct Flags
{
unsigned int is_keyword:1;
unsigned int is_extern:1;
unsigned int is_static:1;
};

This creates three variables of 1-bit each.

But bitfields are very implementation dependant and generally no assumptions can be made. For isntance, it is not known whether the bits above are packed or aligned on 1, 2, 4 or 8 byte bounderies.

Only integers can be declared as bitfields.

In general I would go for the solution used by most APIs. Create a header that contains #defines that check the current compiler and then defines new types to match the same sizes you want.

#ifdef _win32
#define INT32 int
#define INT16 short
#endif

and so on for other systems also.
Jacob Marner, M.Sc.Console Programmer, Deadline Games
Peaceman
Peaceman
why did you forget the easiest solution?

short = 16 bit integer
long = 32 bit integer
double= 64 bit integer

Did I missunderstand the question or what?
felonius
felonius
quote:
Original post by Peaceman
why did you forget the easiest solution?

short = 16 bit integer
long = 32 bit integer
double= 64 bit integer

Did I missunderstand the question or what?


Double is a floating point value not an integer, but it is true that it is a 64-bit floating point value.

I guess you don''t know C. Those sizes are correct on a Intel 32-bit PC. They are not true in general - and no sizes are given in the C and C++ standard.

For instance on the Digital Alpha 64-but arhitecture the following is the case:

short = 16 bit
int = 32-bit
long = 64-bit

or on a 80286 processor (if I recall correctly):

short = 16 bit
int = 16 bit
long = 16 bit
Jacob Marner, M.Sc.Console Programmer, Deadline Games
Peaceman
Peaceman
quote:

I guess you don''t know C. Those sizes are correct on a Intel 32-bit PC. They are not true in general - and no sizes are given in the C and C++ standard.



Yeah, you''re right about me not knowing C. I started with C++ so I didn''t actually quite see the problem :-D

Thanks for explaining it to me anyway.
Crispy
Crispy
Continuing Wyrframe''s question - is it possible to create custom sized variables (I don''t think anyone''s actually found an answer to it in this thread)? Let''s suppose I do want to create a 24-bit integer type variable with the very same properties as a regular integer? felonius, is there a way to make sure that my new-sized variable will behave correctly if I use it, for instance, in: fread(ptr, sizefo(myVar), n, stream)??

Does anyone know how the built in variables in C/C++ are defined?

Crispy
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
felonius
felonius
quote:
Original post by Crispy
Continuing Wyrframe's question - is it possible to create custom sized variables (I don't think anyone's actually found an answer to it in this thread)? Let's suppose I do want to create a 24-bit integer type variable with the very same properties as a regular integer? felonius, is there a way to make sure that my new-sized variable will behave correctly if I use it, for instance, in: fread(ptr, sizefo(myVar), n, stream) ??



You can't create actual new basic types. The closest you get is by using bit-fields as part of a struct but as said there is no garantee that they are packed and it will probably include passing so if we have

struct myType
{
myVar:24;
};

then sizeof(myType) will likely be 4 or 8 depending on the compiler - not 3 as you might want.


and it certainly will not work with fread.

quote:

Does anyone know how the built in variables in C/C++ are defined?



The built-in types are built-in so they cannot be defined in the language itself, if that is what you mean. The only requirement in the C standard concerning size is that

sizeof(short) <= sizeof(int)
sizeof(int) <= sizeof(long)
sizeof(float) <= sizeof(double)
sizeof(double) <= sizeof(long double)
You cannot say anything about sizeof(char). You cannot assume it is 1.

[edited by - felonius on June 16, 2002 12:34:58 PM]

[edited by - felonius on June 16, 2002 12:35:36 PM]
Jacob Marner, M.Sc.Console Programmer, Deadline Games
tsuraan
tsuraan
Doesn''t the C spec say that sizeof(char) returns 1? Or is that out of date?
jaxson
jaxson
quote:
Original post by tsuraan
Doesn''t the C spec say that sizeof(char) returns 1? Or is that out of date?


You are correct. sizeof() always returns 1 for type char.
felonius
felonius
quote:
Original post by tsuraan
Doesn't the C spec say that sizeof(char) returns 1? Or is that out of date?


I don't own the official standard document (ISO sells it from their website - maybe I should buy one) but in the Reference Manual in the back of Kernighan & Ritchie: The C Programming Language in section A4.2 it says:

"Objects declared as characters (char) are large enough to store any member of the execution character set. If a genuine character from the set is stored in a char object, its value is equivalent to the integer code for the character, and is non-negative. Other quantities may be stored into char variables, but the available range of values, and especially whether the value is signed, is implementation-dependent."

So the size of char and even whether it is signed or unsigned by default is compiler dependent. In practice, however, so many programs assume that sizeof(char)=1 that nobody would dare make a compiler that did not do this.

quote:
Original post by jaxson
You are correct. sizeof() always returns 1 for type char.


So no, it doesn't. On all the machines I know it does, but this is not garanteed.

[edited by - felonius on June 16, 2002 2:08:57 PM]
Jacob Marner, M.Sc.Console Programmer, Deadline Games
felonius
felonius
Better now than later. I have bought a copy of both the C and C++ standards on-line from ANSI. The phrasing from above is repeated in the standard. Furthermore, the standard states that:

sizeof(char) >= 1
sizeof(short) >= 2
sizeof(int) >= 2
sizeof(long) >= 4
sizeof(long long) >= 8
Jacob Marner, M.Sc.Console Programmer, Deadline Games
Promit
Promit
VC++, at least, allows you to specify how structures should be packed in the compiler options, and in the compiler command line(you can use a pragma too).

Shouldn''t it be possible to force a 4 byte pack like this:
struct __int24
{
int theInt:24;
__int8 unused;
}
?

____________________________________________________________
Direct3D vs. OpenGL
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
felonius
felonius
quote:
Original post by Promit
VC++, at least, allows you to specify how structures should be packed in the compiler options, and in the compiler command line(you can use a pragma too).

Shouldn''t it be possible to force a 4 byte pack like this:
struct __int24
{
int theInt:24;
__int8 unused;
}
?



Possibly, you could try it out. But be aware that you are then completely MVC++ specific.

You could write like this:

#pragma pack(1)
struct __int24
{
int theInt:24;
__int8 unused;
}
#pragma pack()

It might work but it is completely compiler dependent and it will not work on other systems.
Jacob Marner, M.Sc.Console Programmer, Deadline Games
Null and Void
Null and Void
The value of sizeof(char) is ALWAYS one, since sizeof returns the size of the data type measured in characters. The sizeof operator does not return the number of bytes of the data type. I''ll find the reference to this (again) in the C99 Draft if I have to .

Conner McCloud
Conner McCloud
Which standard states the minimum sizes for the types? From my reading, I've been lead to believe that in C, sizeof returns the number of bytes a type occupies, but in C++ sizeof returns the number of chars a type occupies. So in C++, sizeof(char) always returns 1, but in C sizeof(char) may return 2 if you have two byte char values.

ex:
char is 2 bytes; C sizeof(char) == 2; C++ sizeof(char) == 1
short is 2 bytes; C sizeof(short) == 2; C++ sizeof(short) == 1
int is 4 bytes; C sizeof(int) == 4; C++ sizeof(int) == 2
double is 8 bytes; C sizeof(double) == 8; C++ sizeof(int) == 4

CM

[edit] It sounds like Null and Void is pretty positive sizeof in C works the same way it does in C++, so that half of what I just said should probably be disregarded. I wasn't completely certain about that part anyhow.[/edit]

[edited by - Conner McCloud on June 16, 2002 5:56:44 PM]
Null and Void
Null and Void
WG14/N869   Committee Draft -- January 18, 1999   81

6.5.3.4 The sizeof operator
...
Semantics
...
When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.
...
felonius
felonius
quote:
Original post by Null and Void
WG14/N869   Committee Draft -- January 18, 1999   81

6.5.3.4 The sizeof operator
...
Semantics
...
When applied to an operand that has type char , unsigned char , or signed char , (or a qualified version thereof) the result is 1.
...


Ups.

Okay, I found this in the final version of the C++ Standard in section 5.3.3 and it states the same thing. And in the C Standard 6.5.3.4 (as mentioned above). So I give in sizeof(char) is always 1 - in both C and C++. We learn something every day.


[edited by - felonius on June 16, 2002 6:14:44 PM]
Jacob Marner, M.Sc.Console Programmer, Deadline Games
felonius
felonius
quote:
Original post by Conner McCloud
Which standard states the minimum sizes for the types? From my reading, I''ve been lead to believe that in C, sizeof returns the number of bytes a type occupies, but in C++ sizeof returns the number of chars a type occupies. So in C++, sizeof(char) always returns 1, but in C sizeof(char) may return 2 if you have two byte char values.

ex:
char is 2 bytes; C sizeof(char) == 2; C++ sizeof(char) == 1
short is 2 bytes; C sizeof(short) == 2; C++ sizeof(short) == 1
int is 4 bytes; C sizeof(int) == 4; C++ sizeof(int) == 2
double is 8 bytes; C sizeof(double) == 8; C++ sizeof(int) == 4

CM

[edit] It sounds like Null and Void is pretty positive sizeof in C works the same way it does in C++, so that half of what I just said should probably be disregarded. I wasn''t completely certain about that part anyhow.[/edit]



Well, since we have now cleared up that a char is both 1 byte large in both C and C++ that difference doesn''t really matter any more.
Jacob Marner, M.Sc.Console Programmer, Deadline Games
mcfly
mcfly

    
#include <limits.h>


template<unsigned int I> struct IDENTIFY {};

#ifdef you_do_not_want_your_compiler_to_report_an_error_if_the_size_couldnt_be_determined


template<> struct IDENTIFY<0>
{
typedef void TYPE;
enum {SUPPORTED=0};
};


#endif


template<> struct IDENTIFY<1> { typedef signed char TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<2> { typedef signed short TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<3> { typedef signed long TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<4> { typedef signed long long TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<5> { typedef signed int TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<6> { typedef unsigned char TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<7> { typedef unsigned short TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<8> { typedef unsigned long TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<9> { typedef unsigned long long TYPE; enum {SUPPORTED=1}; };
template<> struct IDENTIFY<10> { typedef unsigned int TYPE; enum {SUPPORTED=1}; };

template<unsigned int N,bool B> struct SIZETYPE {};

#define DECLARE_SIZETYPE_SIGNED(s,b) \

template<> struct SIZETYPE<s,b>
{
enum
{
I = sizeof( signed char ) * CHAR_BIT == s ? 1 :
sizeof( signed short ) * CHAR_BIT == s ? 2 :
sizeof( signed long ) * CHAR_BIT == s ? 3 :
sizeof( signed long long ) * CHAR_BIT == s ? 4 :
sizeof( signed int ) * CHAR_BIT == s ? 5 :
0
};

typedef IDENTIFY<I>::TYPE TYPE;
enum {SUPPORTED=IDENTIFY<I>::SUPPORTED};
};



#define DECLARE_SIZETYPE_UNSIGNED(s,b) \

template<> struct SIZETYPE<s,b>
{
enum
{
I = sizeof( unsigned char ) * CHAR_BIT == s ? 6
sizeof( unsigned short ) * CHAR_BIT == s ? 7
sizeof( unsigned long ) * CHAR_BIT == s ? 8
sizeof( unsigned long long ) * CHAR_BIT == s ? 9
sizeof( unsigned int ) * CHAR_BIT == s ? 10
0
};

typedef IDENTIFY<I>::TYPE TYPE;
enum {SUPPORTED=IDENTIFY<I>::SUPPORTED};
};


DECLARE_SIZETYPE_SIGNED ( 8, true )
DECLARE_SIZETYPE_UNSIGNED ( 8, false )
DECLARE_SIZETYPE_SIGNED ( 16, true )
DECLARE_SIZETYPE_UNSIGNED ( 16, false )
DECLARE_SIZETYPE_SIGNED ( 32, true )
DECLARE_SIZETYPE_UNSIGNED ( 32, false )
DECLARE_SIZETYPE_SIGNED ( 64, true )
DECLARE_SIZETYPE_UNSIGNED ( 64, false )


typedef SIZETYPE< 8, true >::TYPE I8;
typedef SIZETYPE< 8, false >::TYPE U8;
typedef SIZETYPE< 16, true >::TYPE I16;
typedef SIZETYPE< 16, false >::TYPE U16;
typedef SIZETYPE< 32, true >::TYPE I32;
typedef SIZETYPE< 32, false >::TYPE U32;
typedef SIZETYPE< 64, true >::TYPE I64;
typedef SIZETYPE< 64, false >::TYPE U64;


enum { I8_SUPPORT = SIZETYPE< 8, true >::SUPPORTED };
enum { U8_SUPPORT = SIZETYPE< 8, false >::SUPPORTED };
enum { I16_SUPPORT = SIZETYPE< 16, true >::SUPPORTED };
enum { U16_SUPPORT = SIZETYPE< 16, false >::SUPPORTED };
enum { I32_SUPPORT = SIZETYPE< 32, true >::SUPPORTED };
enum { U32_SUPPORT = SIZETYPE< 32, false >::SUPPORTED };
enum { I64_SUPPORT = SIZETYPE< 64, true >::SUPPORTED };
enum { U64_SUPPORT = SIZETYPE< 64, false >::SUPPORTED };


void main()
{
if (I8_SUPPORT)
{
I8 heureka = 10;
}
}




[edited by - mcfly on June 16, 2002 6:24:59 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.