Sign in to follow this  
skwee

MAKE VERSION macro? How to do?

Recommended Posts

skwee    337
Hello i want to do preprocessor MACRO like MAKEVERSION(a,b,c,d) and after i'll call it like this MAKEVERSION(0,2,3,56) i'll get a DWORD = 0.2.3.56 Is it possible? Thanks

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by Minios
Hello i want to do preprocessor MACRO like MAKEVERSION(a,b,c,d)
and after i'll call it like this MAKEVERSION(0,2,3,56) i'll get a DWORD = 0.2.3.56
Is it possible?
Thanks
Not exactly, since a DWORD can only store one integer.
You can however, pack the values in so you'd get DWORD = 0x00020338, which represents what you want with the following:

#define MAKEVERSION(a, b, c, d) (DWORD)( (((a)&0xff)<<24) | (((a)&0xff)<<16) | (((a)&0xff)<<8) | ((a)&0xff))




EDIT: Screwed up the masks

Share this post


Link to post
Share on other sites
Sly    128
#define MAKEVERSION(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))

will give you

DWORD version = 0x0a0b0c0d

The only limit on this is that each number must be between 0 and 255.

To print out the version number as a string,

printf("Version: %d.%d.%d.%d", (version & 0xff000000) >> 24, (version & 0x00ff0000) >> 16, (version & 0x0000ff00) >> 8, version & 0x000000ff);

Share this post


Link to post
Share on other sites
skwee    337
Big Thanks!! :D
And how i can print it in this way: 0.2.3.56?
I mean when i;m doing printf i'm getting a long number like 106842335..
Thanks again.

Sorry didnt noticed Sly's comment
Thanks ppl :)

Share this post


Link to post
Share on other sites
demonkoryu    980
typedef unsigned long dw;

dw v = MAKEVERSION(1,2,3,4);

dw a=(v >> 24) & 0xff;
dw b=(v >> 16) & 0xff;
dw c=(v >> 8) & 0xff;
dw d=v & 0xff;
printf("%u.%u.%u.%u.", a, b, c, d);

Share this post


Link to post
Share on other sites
demonkoryu    980
[quote]Original post by Evil Steve

#define MAKEVERSION(a, b, c, d) (DWORD)( (((a)&0xff)<<24) | (((b)&0xff)<<16) | (((c)&0xff)<<8) | ((d)&0xff))


[/quote]
Fixed it for you.

Share this post


Link to post
Share on other sites
Antheus    2409
Since you mention DWORDS, it's likely you're talking about C++.


typedef unsigned char ver_t;

template < ver_t A, ver_t B, ver_t C, ver_t D >
struct version
{
DWORD operator()() const
{
return (A << 24) | (B<<16) | (C<<8) | (D);
}

ver_t Version() const { return A; }
ver_t Major() const { return B; }
ver_t Minor() const { return C; }
ver_t Build() const { return D; }

void print() const
{
std::cout << static_cast<int>(A) << '.'
<< static_cast<int>(B) << '.'
<< static_cast<int>(C) << '.'
<< static_cast<int>(D);
}
};

typedef version<0,2,3,56> BuildVersion;
typedef version<1,0,0,22> ProtocolVersion;

....



You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

But the best thing is, there is no overhead, there is no storage, and no #defines.

You can optionally make all methods static.

Excercises left for the reader:
- overload << operator
- overload comparison operators
etc...

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by Konfusius
Quote:
Original post by Evil Steve
*** Source Snippet Removed ***

Fixed it for you.

Whoops, damn copy & paste errors...

Share this post


Link to post
Share on other sites
demonkoryu    980
Quote:
Original post by Antheus
Since you mention DWORDS, it's likely you're talking about C++.

*** Source Snippet Removed ***

Nice solution, but...

Quote:

You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

And watch it blow up?

Quote:
But the best thing is, there is no overhead, there is no storage, and no #defines.

Maybe 4 times as much storage than the macro solution.

Quote:
You can optionally make all methods static.

To what effect?

Quote:
Excercises left for the reader:
- overload << operator
- overload comparison operators
etc...

Comparison operators. Forgot that you have to define a different type for every version?

For DWORDS, comparison operators are built in.

Share this post


Link to post
Share on other sites
Bregma    9214
Quote:
Original post by Konfusius
Quote:
Original post by Antheus
Since you mention DWORDS, it's likely you're talking about C++.

*** Source Snippet Removed ***

Nice solution, but...

Quote:

You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

And watch it blow up?

Why would it blow up?
Quote:

Quote:
But the best thing is, there is no overhead, there is no storage, and no #defines.

Maybe 4 times as much storage than the macro solution.

Or maybe no storage. Oh, it's true that the values would appear in the DATA segment, just like with the C preprocessor macro, but there's no need for the additional non-portable DWORD with the template.
Quote:

Quote:
You can optionally make all methods static.

To what effect?

So you don't need an instance variable.
Quote:

Quote:
Excercises left for the reader:
- overload << operator
- overload comparison operators
etc...

Comparison operators. Forgot that you have to define a different type for every version?

For DWORDS, comparison operators are built in.

So you can compare apple.verision and orange.version and get meaningful results, yes?

Share this post


Link to post
Share on other sites
Julian90    736
Quote:
Original post by Bregma
Quote:
Original post by Konfusius
Quote:
Original post by Antheus
Since you mention DWORDS, it's likely you're talking about C++.

*** Source Snippet Removed ***

Nice solution, but...

Quote:

You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

And watch it blow up?

Why would it blow up?


As it stands operator() would fail.


// Fixed operator()
// Fixed print using type_traits to avoid the static cast which would
// cause errors if sizeof(ver_t) > sizeof(int)

typedef unsigned char ver_t;

template < ver_t A, ver_t B, ver_t C, ver_t D, typename CompactType = DWORD >
struct version
{
CompactType operator()() const
{
BOOST_STATIC_ASSERT(4 * sizeof(ver_t) <= sizeof(CompactType));
std::size_t bits = sizeof(ver_t) * CHAR_BITS;
return (A << 3 * bits) | (B << 2 * bits) | (C << bits) | (D);
}

ver_t Version() const { return A; }
ver_t Major() const { return B; }
ver_t Minor() const { return C; }
ver_t Build() const { return D; }

private:
template<typename T>
struct print_traits
{
T convert(t)
{ return t; }
};

template<>
struct print_traits<char>
{
int convert(char c)
{ return static_cast<int>(c); }
};

template<>
struct print_traits<unsigned char>
{
int convert(unsigned char c)
{ return static_cast<int>(c); }
};

template<>
struct print_traits<signed char>
{
int convert(signed char c)
{ return static_cast<int>(c); }
};

void print() const
{
std::cout << print_traits<ver_t>::convert(A) << '.'
<< print_traits<ver_t>::convert(B) << '.'
<< print_traits<ver_t>::convert(C) << '.'
<< print_traits<ver_t>::convert(D);
}
};

Share this post


Link to post
Share on other sites
NotAYakk    876
Antheus, you should store the "DWORD" value as a value in an enum.

This gives you a compile-time constant if you absolutely need it.

Share this post


Link to post
Share on other sites
CmpDev    100
This is all getting a bit too fancy, this is what I have used in the past. The enum is just there is you want to find the patch or major etc.

#ifndef GNL_VERSION_H_
# define GNL_VERSION_H_

# include "GNL_types.h"
# include <string>
# include <sstream>

namespace GNL
{

///////////////////////////////////////////////////////////////////////////////
/// Build
/// A simple version build number which is sent when connecting to determine
/// if the client is using the correct version of the library
///////////////////////////////////////////////////////////////////////////////
template<GNL::uint8 MAJ,GNL::uint8 MIN,GNL::uint8 PATCH>
struct Build
{
enum {major = MAJ,minor = MIN,patch = PATCH};
static GNL::uint32 number()
{
static GNL::uint32 version_number = (GNL::uint32)major*1000+minor*100+patch;
return version_number;
}
static std::string str()
{
std::stringstream s;
s <<"OpenGNL-"<<major <<"." <<minor <<"." <<patch;
return s.str();
}
};

typedef Build<0,3,1> Version;//this is the build

}//GNL

#endif//GNL_VERSION_H_

Share this post


Link to post
Share on other sites
demonkoryu    980
Quote:
Original post by Bregma
Why would it blow up?

Because that implementation doesn't work with values greater than 255.

Quote:
Or maybe no storage. Oh, it's true that the values would appear in the DATA segment, just like with the C preprocessor macro, but there's no need for the additional non-portable DWORD with the template.

Well, I bet many compilers will store 1 machine word for every version component. And what's that about non-portability? The OP asked for a DWORD (and a macro), nothing more, nothing less.

Quote:

Quote:

Quote:
You can optionally make all methods static.

To what effect?

So you don't need an instance variable.

Bad style.

Quote:
So you can compare apple.verision and orange.version and get meaningful results, yes?

Yeah, exactly that. if (current_version < needed_version) throw version_error(); or something like that. No need for overengineering.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this