0

There is a debug class that is used to print out debug statements based on a level. The higher the level, the more detailed messages you would get. The problem occurs when I am trying to do print out a uint64_t. On different platforms using printf style it could be either %li or %lli. I want it to become portable. However, based on this, I could include a PRId64 and it would adjust accordingly. The problem is because my messages are customized, it takes in a const char *. I am unable to do with with a message such as "Calling based on pts %"PRId64, mv.pts because it is expecting a char * where there isn't one. What are other approaches in solving this?

Inside the main code

#include "debug.h"
#include <inttypes.h>    

#define P_DBG(level, format, ...) DBGPRINT(level, ("%-5d%s::%s() - " format "\n", __LINE__, str().c_str    (), __FUNCTION__, __VA_ARGS__))
#define P_ALL(format, ...) P_DBG(P_ALWAYS, format, __VA_ARGS__)
class Something 
{
    Something::Print(uint64_t a) {
        P_ALL("Calling based on %"PRId64 "\n", a)
}

Inside debug.h

class vdebugPrint {
class vdebugPrint(int ID, int level) : v_id(ID), v_level(level) {}
int Print(const char* formatString, ...) __attribute__((__format(printf,2,3)));
}
...
#define VPRINT3(level, msg)    VdebugPrint(ID, level).Print msg
#define PRINT(level, msg)     VPRINT##level(level,msg)
#define DBGPRINT(level, msg)     PRINT(level,msg)
...

Inside debug.cpp

...
VdebugPrint::Print(const char* format, ...)
{
    va_list argumentList;
    va_start(argumentList, formatString);
    vprintf(formatString, argumentList);
    va_end(argumentList);
}

The exact error message is

error: expected ‘)’ before ‘PRId64’
     AV_TRACE("Calling based on %"PRId64"\n", mv.pts);
                                  ^
/.../debug.h:140:94: note: in definition of macro ‘VPRINT3’
 #define VPRINT3(level, msg)      VdebugPrint(ID, level).DebugPrint msg

/.../debug.h:146:45: note: in expansion of macro ‘DBGPRINT’
 #define DBGPRINT(level, msg)            PRINT(level, msg)
                                         ^
/.../file.h:54:41: note: in expansion of macro ‘DBGPRINT’
#define P_PBD(level, format, args...)  DBGPRINT(level, ("%-5d%s::%s() - " format "\n", __LINE__, str().c_str(), __FUNCTION__, ##args))

EDIT:

I've attempted Olaf suggestion to no avail. Here is what I've done. Everything else is the same except for the main code.

...
class Something
{
    Something::Print(uint64_t a) {
        const char* message = "Calling based on %";
        size_t mlen = strlen(message);
        char buf[mlen + strlen(PRId64) + 1];
        strcpy(buf, message);
        strcpy(buf + mlen, PRId64);

        P_ALL(buf, a);
    }
}

The error that I get is

error: ‘PRId64’ was not declared in this scope
     char buf[mlen + strlen(PRId64) + 1];
                            ^

EDIT2: So I fixed the problem with it not finding PRId64. I had to define __STDC_FORMAT_MACROS from here before include inttypes. This now solves the problem and it compiles!

Community
  • 1
  • 1
TheBlueMan
  • 316
  • 1
  • 4
  • 27
  • 1
    could you post the exact error message? – Andreas Grapentin Jun 18 '15 at 12:50
  • Well, `"Calling based on pts %"PRId64, mv.pts"` is incorrect anyway. You need `"Calling based on pts %"PRId64"", mv.pts`, note the `"` has to move. – EOF Jun 18 '15 at 13:06
  • @EOF: There is no actual need for the last `""`. `PRI*` uses string literal concatenation. It is just a macro giving the appropriae format string. – too honest for this site Jun 18 '15 at 13:15
  • @Olaf: Well, this *is* a bit of a special case, where the conversion specifier is the end of the format string. I was trying to make the point that, in general, the `PRIwhatever` needs to be enclosed in `"`s. – EOF Jun 18 '15 at 13:17
  • It seems that this should work, to be honest.. yes, what's the error messages? – Claudiu Jun 18 '15 at 13:28
  • 1
    @EOF: That is not correct. They are alread string literals. So no ned to enclose in `"` (that would actually not work). I suppose you mean to insert them into another string literal, _that_ has to be broken into two literals, so the whole tripple would be subject to _string literal concatenation_. – too honest for this site Jun 18 '15 at 13:29
  • `class Something` is invalid in C. Did you mean to only tag C++? – M.M Jun 18 '15 at 15:35
  • What compiler and switches are you using? `inttypes.h` may not have been available prior to C++11, and some more recent compilers may only have partial C++11 support – M.M Jun 18 '15 at 15:37

2 Answers2

1

The macros defined in inttypes.h are string literals with the proper printf type specifier. So you have to append this to the format string. Normal usage would be to use string literal concatenation.

If your format string is variable, you have to append the specifier to the string:

char buf[strlen[format] + strlen[PRId64] + 1];
strcpy(buff, format);
strcat(buff, PRId64);

Note this could be optimized using strcpy for both:

size_t flen = strlen(format);
char buf[flen + strlen[PRId64] + 1];
strcpy(buff, format);
strcpy(buff + flen, PRId64);

Caution: The format string has to be NUL-terminated!

Update:

The original answer was for C as that was one of the language-tags and the code looked more like C than C++. However, according to comments, you can use this also for C++11 (check your compiler's support), if you #define __STDC_FORMAT_MACROS before #include <inttypes.h>. (Note the include might appear in other headers, so you should define the macro as early as possibly in your file.)

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • It appears as though the macro is not expanding. This is the error I get when I try this. `error: ‘PRId64’ was not declared in this scope char buf[mlen + strlen(PRId64) + 1];` I have mad sure that `inttypes.h` is included. I have edited my code above to show you what I've done. – TheBlueMan Jun 18 '15 at 14:43
  • @bluestring: As you had the original question tagged C, I did answer according to the standard. That macro is not required by the standard. It is a very bad idea to remove a target language you got an answer for. – too honest for this site Jun 18 '15 at 16:48
  • @bluestring: However, I added a note about C++. – too honest for this site Jun 18 '15 at 17:00
0

You need spaces between the adjacent string literals and the macros for the expansion and concatenation to work. For example:

// Note the space on either side of PRId64
AV_TRACE("Calling based on %" PRId64 "\n", mv.pts);

(I don't know if this is required according to the standard, but it is required to make it work for some preprocessors I've used.)

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175