user1011471
user1011471

Reputation: 1130

C Macro with variable args - "incompatible pointer type"

I'm trying to create a wrapper macro for vsnprintf. I'd like it eventually to log the line number if truncation happens, hence I'm making it a macro so I can use the __LINE __ macro. But the compiler doesn't like what I have so far:

foo.c: In function ‘main’:
foo.c:35:44: warning: passing argument 4 of ‘vsnprintf’ from incompatible pointer type
MYPRINT(buffer,&result,LENGTH,"hello %s","world");
^
foo.c:27:52: note: in definition of macro ‘MYPRINT’
result = vsnprintf(destination,size,format, ## args );  \
^
In file included from foo.c:10:0:
/usr/include/stdio.h:390:12: note: expected ‘struct __va_list_tag *’ but argument is of type ‘char *’
extern int vsnprintf (char *__restrict __s, size_t __maxlen,

My code is below. I'm not sure how to fix it. Perhaps I need to wrap something in parens?

#define LENGTH (512)

#define MYPRINT(destination,result_ptr,size,format,args...) \
  {                                                         \
    int result;                                             \
    result = vsnprintf(destination,size,format, ## args );  \
    *result_ptr = result;                                   \
  }

int main (int argc, char **argv)
{
  int result;
  char buffer[LENGTH];
  MYPRINT(buffer,&result,LENGTH,"hello %s","world");
  fprintf(stderr,"%s\n",buffer);
  return 0;
}

Upvotes: 1

Views: 416

Answers (1)

Remo.D
Remo.D

Reputation: 16522

You don't really need vsnprintf() for this. You should use snprintf() and the __VA_ARGS__ that is to be used with the variadic macros since C99. vsnprintf() is best used with variadic functions, not with variadic macros.

This is a, slightly corrected, version of your code.

#include <stdio.h>
#include <stdarg.h>

#define LENGTH 512

#define MYPRINT(destination,res,size,format, ...) \
  do {                                                      \
    int m_res;                                             \
    m_res = snprintf(destination,size,format, __VA_ARGS__ );  \
    res = m_res;                                   \
  } while (0)

int main (int argc, char **argv)
{
  int result;
  char buffer[LENGTH];
  MYPRINT(buffer,result,LENGTH,"hello %s","world");
  fprintf(stderr,"%s\n",buffer);
  return 0;
}

Note that since MYPRINT is a macro (and not a function) you don't need to pass the pointer to the variable result. You are actually passing the name of the variable itself. As you are doing now you, you will have a conflict between the result declared in the main and the result declared in the macro body block.

I've added the idiom do {} while(0) to ensure the macro is treated as a single statement by the compiler.

Hope it helps.

Upvotes: 1

Related Questions