2

I would like to compute something according to the version of a library (which I can't change the values) by using C language.

However, the version of the library, that I am using, is defined as string by using #defines like:

/* major version */
#define MAJOR_VERSION "2"

/* minor version */
#define MINOR_VERSION "2"

Then, my question is: how to do define the macro STR_TO_INT in order to convert the strings MINOR_VERSION and MAJOR_VERSION to integer?

#if ((STR_TO_INT(MAJOR_VERSION) == 2 && STR_TO_INT(MINOR_VERSION) >= 2) || (STR_TO_INT(MAJOR_VERSION > 2))
    //I perform an action...
#else 
    //I perform a different action
#endif

I prefer to define it as macro since I am using a lot of function from this library. Please feel free to give me any idea.

8
  • 5
    There isn't a way to do the conversion from string to integer in the C preprocessor AFAIK. The other way is easy enough, and you can get the compiler proper to work for you (if ((MAJOR_VERSION[0] - '0') >= 2 && …). But the preprocessor can't handle subscripting. Commented Feb 2, 2016 at 1:24
  • 2
    Note that your test is wrong, too; it will perform 'a different action' for version 3.0, 3.1, 4.0, 4.1, etc. You need if ((NUM_MAJOR_VERSION == 2 && NUM_MINOR_VERSION >= 2) || NUM_MAJOR_VERSION > 2) to do the comparison that is normally needed (every version from 2.2 upwards does 'an action'; older versions do 'a different action'). Commented Feb 2, 2016 at 1:26
  • @Jonathan That restricts the numbers to single digits, with no error or warning if they exceed that, so I would advise against that approach. I would use something like strtol. Commented Feb 2, 2016 at 1:27
  • @TomKarzes: Fair comment. I know of some software that is still using internal version 9.xx even though the external version passed 10.x a while ago — because of that sort of problem (and one day, xx will get too close to 99). It was more a question of "with care you can do it in the compiler" (and can't do it in the preprocessor, even with care) than anything else. Commented Feb 2, 2016 at 1:29
  • Do you have control over your library? Can you preprocess the header to find the current major-minor version information? Have you checked whether there's a numeric equivalent to the major and minor version numbers? Commented Feb 2, 2016 at 1:31

2 Answers 2

3

Preprocess the official library header, libheader.h, to generate your more useful information without the quotes in a new header, libversion.h:

sed -n -e '/^#define \(M[AI][JN]OR\)_VERSION "\([0-9][0-9]*\)".*/ {
                s//#define NUM_\1_VERSION \2/p
           }' libheader.h >libversion.h

You might need to be more flexible about allowing spaces and tabs around the separate parts of #, define and the macro name. I also assume there are no comments in the definition (trailing comments are handled):

/* This starts in column 1 - unlike the next line */
    # define /* No comment here */ MAJOR_VERSION /* Nor here */ "2"

Now you can include both libheader.h and libversion.h and compare the numeric versions with impunity (as long as you get the expressions correct):

#include "libheader.h"
#include "libversion.h"

#if ((NUM_MAJOR_VERSION == 2 && NUM_MINOR_VERSION >= 2) || NUM_MAJOR_VERSION > 2)
    …perform the new action…
#else
    …perform the old action…
#endif

Strictly, the sed script will also convert MIJOR_VERSION and MANOR_VERSION; however, they're unlikely to appear in the library header, and you can ignore the generated numeric versions with ease. There are ways to deal with that if you really think it is an actual rather than hypothetical problem.

More seriously, if the library has complicated controls on the version information, it could be that a single header can masquerade as different versions of the library — there could be multiple lines defining the major and minor versions. If that's the case, you have to work a lot harder.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you Jonathan. I understood it. But, I think I will use your suggestion from the previous comment: to use the if from the compiler. If possible, I would like to know if I can add this sed script into a Make or configure file.
Adding it to a makefile would be trivial. Note the point made by Tom Karze about the string version; if the library might get to version 10 or beyond, my original suggestion won't work well.
Thank you very much! I have add your sed script in my Makefile and it perfectly works!
0

#define MAJOR_VERSION 2 will work anywhere, as an int, as you have, 2, there is no need for string/ conversions. You can directly do:

if (MAJOR_VERSION == 2) { /* version 2 */ }

else { /* not version 2 */ }

7 Comments

Plus, if you want it as a string, too, you can #define MAJOR_VERSION_STRING STRINGIZE(MAJOR_VERSION) with #define STRINGIZE(X) #X. Going the opposite direction is not entirely impossible but much more awkward.
I can't change it since it is defined in the library that I am using.
@AndersonCarniel so there is a #define MAJOR_VERSION 2 (Two being whatever the version is) in the library you are using? In your code it is still just: if (MAJOR_VERSION == 2) { ... } Again, two being whatever version. However, you really shouldn't/ wouldn't use quotes between the numbers.
@EvanCarslake My library means that I am using a library which I can't change the source code.
@AndersonCarniel in the library you are using, there is a version definition, right? In your code that using the library, it has definitions indicating its version? To check its version in your code, you can directly compare as if (MAJOR_VERSION == 2) { ... }. MAJOR_VERSION being defined in the library, and checked in your code.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.