Issue with sprintf

I’ve tripped over this issue before but I’ve not dealt with this for a while and it creeps up on me today again:

The issue is that sprintf has trouble with long and unsigned long type parameter when the formatting string has %d. The following will not give desirable results:

sprintf(buffer, “Time %2d:%02d:%02d”, (millis()/1000/3600), (millis()/1000%3600/60), (millis()/1000%60));

The following will give desirable result:

sprintf(buffer, “Time %2d:%02d:%02d”, int(millis()/1000/3600), int(millis()/1000%3600/60), int(millis()/1000%60));

avr gcc version of sprintf must have some issues. The “issue” version works just fine in dev C++ that uses gcc.

I’ll be more careful next time.

Any insight into this?

liudr:
The issue is that sprintf has trouble with long and unsigned long type parameter when the formatting string has %d. The following will not give desirable results:

%d and %i consume a signed decimal integer (int) by design. You need to add a lowercase L to consume a long datatype … %ld or %li.

Right. I was using %d in dev c++ and supplied an unsigned long in the argument list but I got the right result. I know I was at fault but don’t know why nothing breaks. I wonder if avr gcc and gcc handle these variable length argument lists differently, resulting me not seeing my mistake showing up in regular gcc but showing up in avr gcc.

liudr: I wonder if avr gcc and gcc handle these variable length argument lists differently, resulting me not seeing my mistake showing up in regular gcc but showing up in avr gcc.

It depends more on the intended architecture and not necessarily "avr gcc" versus "regular gcc".

A quick experiment with

printf("int: %d\n", sizeof(int));
printf("long: %d\n", sizeof(long));

On my computer, gcc generating x86 code uses 4 and 8 bytes, which are twice as large as avr.

You are the man James. I got 4 and 4 for int and long on my dev C++ using gcc. So what is controlling this aspect then?

liudr: So what is controlling this aspect then?

It depends on the target architecture.

When writing portable code, it is important to keep in mind that not all architectures define data types the same. gcc conforms to C89/C99 which gives the minimum size of data types, but not maximums. You might like this reference:

http://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Data-Types