0

I use the following function to make automatic notifications for user:

#define LOG(...) logger((sizeof((int32_t[]){0, ## __VA_ARGS__})/sizeof(int32_t)-1), __VA_ARGS__)
..................
void informer(int32_t count, ...)
{
    GtkTreeModel *model = 0;
    GtkTreeIter iter;
    model = gtk_tree_view_get_model(GUI.log_view);
    gtk_list_store_append(GTK_LIST_STORE(model), &iter);
    char log_body[16384] = {0};
    /* Add current time */
    GDateTime *now;     
    char *time;
    now = g_date_time_new_now_local ();
    time = g_date_time_format (now, "%c");
    g_date_time_unref (now);
    gtk_list_store_set(GTK_LIST_STORE(model), &iter, LOG_TIME, time,  -1);
    free(time);
    /* Parse input data*/
    va_list ap;
    va_start(ap, count);
    while (count--) {
        if(!count)
        {
            enum error_type type = va_arg(ap, int);
            if(type == OK)
            {
                gtk_list_store_set(GTK_LIST_STORE(model), &iter, LOG_TYPE, "OK",  -1);

            }
.............................................                       
            else
            {
                gtk_list_store_set(GTK_LIST_STORE(model), &iter, LOG_TYPE, "Неизв.",  -1);
            }
            break;
        }
        char* arg = va_arg(ap, char*);
        strcat(log_body," ");
        strcat(log_body,arg);
    }
    va_end(ap);
    gtk_list_store_set(GTK_LIST_STORE(model), &iter, LOG_BODY, log_body,  -1);
}

So in such a call

LOG("Unknown error", "Error!", ERROR);

where ERROR is enum, gcc show warning during compilation:

warning: (near initialization for ‘(anonymous)[1]’)
warning: initialization makes integer from pointer without a cast [enabled by default]
warning: (near initialization for ‘(anonymous)[2]’)
warning: initialization makes integer from pointer without a cast [enabled by default]
warning: (near initialization for ‘(anonymous)[3]’)
warning: initialization makes integer from pointer without a cast [enabled by default]

The code work perfectly, but is this safe in real? If it is, how to get rid of it? I tried to use #pragma GCC diagnostic error "-Wpointer-to-int-cast" with corresponding push and pop but with no effect.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
pugnator
  • 665
  • 10
  • 27
  • What do you try to achieve? `sizeof((int32_t[]){0, ## __VA_ARGS__})` doesn't look very useful. Do you want to count the number of elements in the varg list? There are other means to achieve that. – Jens Gustedt Sep 16 '13 at 11:04

3 Answers3

1

The macro is valid only where all pointer types are the same size, and where that size is 32-bit. The first condition is true for most systems and can possibly be ignored if your platform is unlikely to be something esoteric, the second condition certainly is not.

That said, even if it were safe, leaving code that issues warnings is not a good idea since, and globally suppressing them is equally unattractive. To suppress the warnings you would have to apply the suppression to every call to the macro rather than just the macro definition itself in which case it would be easier perhaps just to supply the argument count.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • about pointer size. What if I will use memsize types, like size_t instead of int32_t? It will be 32 and 64bit on corresponding system – pugnator Sep 16 '13 at 09:07
  • pointer to integer type conversion and vice verse is not possible without typecasting. Your solution to count the arguments can be used for homogenous type of arguments. – user1969104 Sep 16 '13 at 09:15
  • @user1969104: It is not "my solution", the logger() function used in the macro appears to take the argument count as a parameter, and the macro is an attempt to determine that automatically. A better solution would be to write a log function with a better interface. – Clifford Sep 16 '13 at 21:41
  • @pugnator: The defined type intptr_t or uintptr_t (in stdint.h) is probably a better bet. – Clifford Sep 16 '13 at 21:43
1

You are trying to count the number of arguments in the LOG macro. Please take a look at the possible solutions here.

Community
  • 1
  • 1
user1969104
  • 2,340
  • 14
  • 15
1

The code is valid:

  • First initialization of a uint32_t with a pointer type will never overflow that value. There will be loss of information, but nothing more.
  • Then you also only use the sizeof such a beast, so the compound literal is never evaluated.

From a point of view of errors, yours wouldn't work for 0 parameters, anyhow, so better remove the gccish , ## trick and the game with +-1.

As others said, it is really bad style to impose a bunch of warnings to users of your code. Such a thing should never pass review.

Finally, there are macros that only use standard C (C99) to achieve the same goal, e.g P99_NARG from P99.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177