Reputation: 2824
I perform some calculations, based on the result, I would like to either use a short int or int for some type of data for the remaining program. Can (/How can) this be done sensibly in C or C++? I don't really care about the amount of memory used (i.e., 2 or 4 bytes), my primary aim is to access generic arrays as if they contained data of this type. I would like to avoid code such as the following:
char s[128];
if (result of preliminary calculations was A)
*((int*) s) = 50;
else
*((short int*) s) = 50;
to set the first 4 or 2 bytes of s. A conditional global typedef would be ideal:
if (result of preliminary calculations was A)
typedef int mytype;
else
typedef short int mytype;
I am not that familiar with C++ class templates (yet). Do they apply to my problem? Would I have to change the declarations throughout my program (to myclass< > and myclass< >*)?
Many thanks!
Frank
Edit: The values may not always be aligned. I.e, a int can start at position 21. Thanks for the answers.
Upvotes: 2
Views: 350
Reputation: 215417
Since your stated goal is to store information efficiently on disk, you should learn to stop writing memory images of C/C++ data structures to disk directly and instead serialize your data. Then you can use any of a number of forms of variable-length coding ("vlc") to get the effect you want. The simplest is a coding with 7 bits per byte where the 8th bit is a continuation flag indicating that the value is continued in the next byte. So 259 would be stored as (binary, with continuation bit marked by spacing and byte boundaries marked by ;):
1 0000010 ; 0 0000011
Alternatively you could use the head nibble to signal the number of bytes that will follow, or use a scheme similar to UTF-8 with slightly more overhead but stricter resynchronization guarantees. There are also vlcs with are designed to be parsable and easily resynchronized when reading either forward or in reverse.
Upvotes: 0
Reputation: 23227
You could abuse templates for this purpose. Any code that's subject to the decision would have to be templated based on the int type. One branch would instantiate the int version, the other would instantiate the short int version. This is probably a bad idea*.
Edit
*Well, it's only a bad idea to apply this to your overall architecture. If you have a particular data type that encapsulates the varied behavior, a template should work just fine.
Here's a variation on Aaron McDaid's answer to illustrate it's use with conditions:
#include <iostream>
#include <string>
using namespace std;
template<int x> struct OddOrEven { typedef typename OddOrEven<x-2>::t t; };
template<> struct OddOrEven<0> { typedef short t; };
template<> struct OddOrEven<1> { typedef int t; };
int main() {
cout << "int or short? ";
string which;
cin >> which;
if (which.compare("int") == 0)
cout << sizeof(OddOrEven<1>::t) << endl;
else if (which.compare("short") == 0)
cout << sizeof(OddOrEven<0>::t) << endl;
else
cout << "Please answer with either int or short next time." << endl;
return 0;
}
Upvotes: 1
Reputation: 27153
If the result of the preliminary calculations can be found at compile time, then this can work. Here are some simple examples to show how this can work. To do more complicated examples, see http://en.wikipedia.org/wiki/Template_metaprogramming
using namespace std;
#include <iostream>
template<int x> struct OddOrEven { typedef typename OddOrEven<x-2>::t t; };
template<> struct OddOrEven<0> { typedef short t; };
template<> struct OddOrEven<1> { typedef int t; };
template<bool makeMeAnInt> struct X { typedef short t; };
template<> struct X<true> { typedef int t; };
int main(void) {
cout << sizeof(X<false>::t) << endl;
cout << sizeof(X<true>::t) << endl;
cout << sizeof(OddOrEven<0>::t) << endl;
cout << sizeof(OddOrEven<1>::t) << endl;
cout << sizeof(OddOrEven<2>::t) << endl;
cout << sizeof(OddOrEven<3>::t) << endl;
cout << sizeof(OddOrEven<4>::t) << endl;
cout << sizeof(OddOrEven<5>::t) << endl;
}
I think above is standard C++, but if not I can tell you this work on g++ (Debian 4.3.2-1.1) 4.3.2
Upvotes: 2
Reputation: 19873
This is a code snippet from a project I had a while back.
void* m_pdata;
if (e_data_type == eU8C1){
pimage_data = new unsigned char[size_x * size_y];
}
if (e_data_type == eU16C1){
pimage_data = new unsigned short[size_x * size_y];
}
I hope it can help you
Upvotes: 0
Reputation: 69752
In current C++ standard (C++03), you can't.
In fact you can use some advanced metaprogramming tricks but it will not help most of the time.
In the next standard (C++0x, certainly C++11 in the end), you will be able to use the keyword decltype
to get the type of an expression. If you're using VC10 (VS2010) or GCC 4.4 or more recent, then you already have the feature available.
Upvotes: 1
Reputation: 19362
I think your main problem is how you plan to read the data from s
later on if you don't know what type to read.
If you have that part covered, you can use a union:
union myintegers
{
int ints[32];
short shorts[64];
};
Now simply use the type you want.
myintegers s;
if (result of preliminary calculations was A)
s.ints[0] = 50;
else
s.shorts[0] = 50;
As a step further, you could wrap it all in a class which is constructed with result of preliminary calculations was A
and overrides the operators * and [] to store in one or the other.
But are you sure you want any of that?
Upvotes: 1
Reputation: 239181
For plain C, you could do this using function pointers:
static union { s_int[32]; s_short[64]; s_char[128]; } s;
static void set_s_int(int i, int n)
{
s.s_int[i] = n;
}
static int get_s_int(int i)
{
return s.s_int[i];
}
static void set_s_short(int i, int n)
{
s.s_short[i] = n;
}
static int get_s_short(int i)
{
return s.s_short[i];
}
static void (*set_s)(int, int);
static int (*get_s)(int);
Set them once based on the preliminary calculations:
if (result of preliminary calculations was A)
{
set_s = set_s_int;
get_s = get_s_int;
}
else
{
set_s = set_s_short;
get_s = get_s_short;
}
Then just use the function pointers in the rest of the program:
set_s(0, 50); /* Set entry 0 in array to 50 */
Your file writing function can directly reference s
or s.s_char
depending on how it works.
Upvotes: 4
Reputation: 59673
In C and C++, all type information is defined at Compile-time. So no, you cannot do this.
Upvotes: 2