0

Is it a way to check if define exists having string?

E.g. I have string "ERROR_1000". It's a variable, so #ifdef seems not working. Is it a way to check if ERROR_1000 was defined with #define?

PS: I'm using Qt now, but don't think that it makes difference, though not sure

UPD: seems like many people don't understand the question.

I have somewhere lots of define like

 #define ERROR_1000 "sometext"
 #define ERROR_1001 "someothertext"

And I have a function

 string fun(int id)
{
  //here I got this number and create string "ERROR" + id, for example "ERROR_1000"
  //so is it possible to check here, if there is a define with name ERROR_1000
  //so if define exists return string from that define
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • 1
    So you want to find out (during run-time? compile-time?) whether the constant `"ERROR_1000"` comes from a line like `#define error_str_1000 "ERROR_1000"`? – alk Nov 26 '13 at 16:13
  • @alk string "ERROR_1000" I'm forming from parameter passed to function(int, that is 1000 here). and #define ERROR_1000 "someerrortext". – user3012414 Nov 26 '13 at 16:21
  • So the proposal given by my answer should work. – alk Nov 26 '13 at 16:23
  • In order to check whether "ERROR_1000 was defined with #define" you can use `#if defined(ERROR_1000)`. It is not clear though what you mean by `ERROR_1000` being a variable. You can't define "variables" with `#define`. – AnT stands with Russia Nov 26 '13 at 16:26
  • I think you need to add code - what did you try that failed? it may make your question clearer. – Caribou Nov 26 '13 at 16:32
  • @Caribou tried to make question more clear – user3012414 Nov 26 '13 at 16:36
  • @user3012414 - edited my answer with a response to your edited post, take a look. – ryyker Nov 26 '13 at 17:07
  • @user3012414 - Look at my post for another solution... – ryyker Nov 26 '13 at 17:22
  • Just made one more edit to my post, modification to your function to use #defines as defined either 1 or 0, then passed as argument. No switch() statement needed. – ryyker Nov 26 '13 at 17:34
  • Look at answer again, changed argument in `fun()`to `char *` to accommodate string macros instead of integer macros. – ryyker Nov 26 '13 at 18:23

4 Answers4

1

Regarding: E.g. I have string ERROR_1000. It's a variable :

If ERROR_1000 is defined as a string, the pre-processor #ifdef will not see it as "defined" eg:

char string[]="teststring";

int main(void)
{
#ifdef teststring
    printf("%s", teststring);
#endif
    return 0;
}

The printf() statement will not execute because string is not recognized by #ifdef.
However, if you define it using #define teststring...

#define teststring "teststring"

int main(void)
{
#ifdef teststring
    printf("%s", teststring);
#endif
    return 0;
}

The `printf() statement will be executed.

Note, if you have a variable named "ERROR_1000". then you cannot also have a #define ERROR_1000. You would have to change one of them to use them together in the same code. eg: (the following will work)

#define ERROR_1000  "not defined"
char Error_1000[]="some other error message";

int main(void)
{
#ifdef ERROR_1000
    printf("%s", Error_1000);
#else
    printf("%s", ERROR_1000);
#endif
    return 0;
}

Note also: statements used in C starting with #, such as #ifdef, or #define are all directives to the environment to preprocess or evaluate before running, or at compile time.
Statments such as if(), or while() are evaluated at run-time.

Regarding the latest edit to your post:
I think using the combination of #define, #ifdef and a switch() statement, you can do what you want...
Maybe this will work for you?:

#define ERROR_1000
#define ERROR_3000
string fun(int id)
{
  buf errorMsg[80];
  sprintf(errorMsg, "ERROR_%d", id);
  switch(id){
    case 1000://this one will print
#ifdef ERROR_1000
        printf("%s", errorMsg);
#endif
        break;
    case 2000://this one will NOT print
#ifdef ERROR_2000
        printf("%s", errorMsg);
#endif


        break;
    case 3000://this one will print
#ifdef ERROR_3000
        printf("%s", errorMsg);
#endif
        break;
  }



  //here I got this number and create string "ERROR" + id, for example "ERROR_1000"
  //so is it possible to check here, if there is a define with name ERROR_1000
  //so if define exists return string from that define
}  

Option without using switch() (modify your function to use the #defines)
Perhaps some variation of this will work...?

#define ERROR_1000 "ERROR_1000"  //will print
#define ERROR_2000 ""  //will not print
#define ERROR_3000 "ERROR_3000"  //will print

void fun(int id, char *print);

int main(void)
{
      fun(1000, ERROR_1000);
      return 0;
}

void fun(int id, char *print)
{
      char errorMsg[80];

     if(strlen(print)>0)
     {
           sprintf(errorMsg, "ERROR_%d is %s", id, print);
           printf("%s", errorMsg);
     }
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • It's first case. I know that it won't work like that so asking here =) – user3012414 Nov 26 '13 at 16:23
  • If you are saying the first example I used is what you have in your code, then no, You cannot use #ifdef to determine if the string ERROR_1000 has been defined. If a ***variable*** it is not defined before it is used (such as ERROR_1000), you will get a compile error. Look at my second example to see how you can use a #define. – ryyker Nov 26 '13 at 16:26
  • I know that I cannot check it using #ifdef, I'm asking is it possible to check somehow other way – user3012414 Nov 26 '13 at 16:29
  • Yes, As I mentioned in my last comment, if say Error_1000 is suppose to be defined as a char [], but it has not yet been declared in your code before you try to use it, then the code will not even compile. So, when it comes to variables, determining if they are defined is automatic. They either are or they are not. ***However*** if you want to test a pre-processor define, it has to be created using #define (to _define_) or #undef (to _un-define_). Much different than for variables. (see edit in my post for clarification) – ryyker Nov 26 '13 at 16:42
  • to your last edit: that is exactly what I'm trying to avoid - having a veeeeeeeeeeeeeeery long switch =) But seems there is no other way :( – user3012414 Nov 26 '13 at 17:15
  • Yeah, sorry, that is the only way I can think of. Did @AndreyT's comment under your post make sense to you? Perhaps that will help. (pretty sure it is also assuming you are _only_ using a #define, and not variables also) – ryyker Nov 26 '13 at 17:17
  • for last modufucation: I have "ERROR_1000", not ERROR_1000 – user3012414 Nov 26 '13 at 17:45
  • @user3012414 - Hmmm, Perhaps you can test the value of your "ERROR_1000" defines in the function argument as a string (instead of an int), and use `strlen()`. i.e. `if(strlen(ERROR_1000) > 0)`, and assign values to your `#defines` such that if you want that type of error printed, make sure it has a string, if you don't want that type printed, just assign an empty string to it ( "" ). – ryyker Nov 26 '13 at 17:59
  • again, I have string. "ERROR_1000" is a string. So not if(strlen(ERROR_1000) > 0) but if(strlen("ERROR_1000") > 0) which makes no sence – user3012414 Nov 26 '13 at 18:03
  • @user3012414 - if you do #define ERROR_1000 "ERROR_1000"` and #define ERROR_1001 "" Then strlen(ERROR_1000)` == 10, while strlen(ERROR_1001) == 0. So that will work as a way to print only those errors you have chosen to print by the value you assign to your #defines. Again, redefine the function so that a second argument is a `char *`, pass the appropriate #define, then in the function, test the 2nd argument for string length greater than 0 as a criteria for whether to printf. ***See my latest edit to the function*** – ryyker Nov 26 '13 at 18:18
  • I cannot pass to the function ERROR_1000. I have only "ERROR_1000" that is in some variable. – user3012414 Nov 26 '13 at 18:57
  • Your last comment is confusing. In your original post you state that you have lots of defines like `#define ERROR_1000 "sometext"`, but now you are saying you cannot pass to the function `ERROR_1000`. Are you not able to change the prototype of the function `fun(int id);` to `void fun(int id, char *print)`? If you can, then you _can_ pass `ERROR_1000` as an argument, eg `fun(1000, ERROR_1000);` This will work the way I have it prototyped in the last section of my answer. – ryyker Nov 27 '13 at 16:02
  • Also, one more thing: `string fun(int id);` is how you have your example function defined in the original post, but it is invalid because _string_ is not a ***[C type](http://en.wikipedia.org/wiki/C_data_types)***. What you probably meant is `char * fun(int id);` Its really academic though, because as far as I can see, you are not returning anything, so it should just be a void return type: `void fun(,);` One suggestion: Google the difference between C variables and #defines (or macros) For starters, here is a ***[good post](http://stackoverflow.com/q/11079450/645128)*** – ryyker Nov 27 '13 at 16:33
0

Try this:

#ifdef ERROR_1000
printf("ERROR_1000 defined");
#else
printf("ERROR_1000 not defined");
#endif

Referring your update:

is it possible to check here, if there is a define with name ERROR_1000

No.

It is not possible per defintion to check whether some #define exist's or not during run-time, as such are gone then. It is even not possible at compile time, at they are also already gone by having been (re-)placed everytime they where used in thr sources by the pre-processor.


A possible approach:

typedef enum errors_e
{
  no_error = 0
  error_1 = 1,
  error_oom = 1,
  error_2 = 2,
  error_disk = 2, 
  ...
  error_9999 = 9999;
  error_unknown = 9999,
} error_code_t;

typedef struct error_message_s
{
  const error_code_t ec;
  const char * et;
} error_message_t

#define ERROR_0001 "out of memory"
#define ERROR_0002 "general failure reading hard disk"
...
#define ERROR_9999 "unkown error"

const error_message_t error_messages[] = {
  { error_1, ERROR_0001 },
  { error_2, ERROR_0002 },
  ...
  { error_9999, ERROR_9999 },
};

const char * fun(error_code_t id)
{
  size index_to_error_messages_array;

  /* Add some clever logic to finds the index to the element 
     in error_messages where ec equals id here .*/

  return error_messages[index_to_error_messages_array]; 
}
alk
  • 69,737
  • 10
  • 105
  • 255
  • no, it's not ERROR_1000, it's . std::string er = "ERROR_1000"; or char er[] = "ERROR_1000"; or whatever. – user3012414 Nov 26 '13 at 16:30
  • As you've already read, if ERROR_1000 is a variable, and it is referenced _before_ it is _declared_. Your code will not build. There is a subtle difference between something being defined using `#define`, and something else being defined by `char er[]="ERROR_1000"` With one, you can test with `#ifdef`, with the other, if it is not defined you will not even be able to compile your code. – ryyker Nov 26 '13 at 16:53
0

Like it's name says, the preprocessor #ifdef is to check on compile time, if you want to make a desicion on run-time you need to use a normal if statement.

If the ERROR_1000 is a parameter, the right way should be:

int main(int argc, char* argv){
   if(argc>1){
      if(argc[1]=="ERROR_1000"){
        // some action
      }
   }
}
fernando.reyes
  • 597
  • 2
  • 15
0

So, you have a variable containing the string "ERROR_1000", and you want to determine if the corresponding ERROR_1000 macro has been #defined.

Unfortunately, there's no good way to make that determination at runtime in C. After preprocessing, the macro ceases to exist; there's no ERROR_1000 defined in the compiled code. Instead, every instance of ERROR_1000 was replaced with the string "sometext" before the code was compiled.

The following is an extremely ugly workaround, but it should work: build a lookup table where the macro name is the key, but it's only included if the macro is defined:

#define ERROR_1000 "sometext"
#define ERROR_1001 "some other text"
...
#define SEP
struct {
  char *errcode;
  char *errtext;
} code_lookup_table[] = {

#if defined( ERROR_1000 )
  SEP  { "ERROR_1000", ERROR_1000 } 
#define SEP ,
#endif

#if defined ( ERROR_1001 )
  SEP { "ERROR_1001", ERROR_1001 } 
#define SEP ,
#endif
...
};

If both ERROR_1000 and ERROR_1001 are defined, then the preprocessed code will look something like

struct {
  char *errcode;
  char *errtext;
} code_lookup_table[] = {

  { "ERROR_1000", "sometext" }

, { "ERROR_1001", "some other text" }

  ...
};

However, I suggest you re-think this use case; this smells like a problem in your design.

John Bode
  • 119,563
  • 19
  • 122
  • 198