Why is snprintf giving different value in second case. Is it because any integer limit. Can you please explain how snprintf works and why the reason for that negative value
#include <stdio.h>
#include <string.h>
main()
{
char buff[256];
snprintf(buff,256,"%s %d"," value",1879056981);
printf("%s",buff);
}
output:
value 1879056981
#include <stdio.h>
#include <string.h>
main()
{
char buff[256];
snprintf(buff,256,"%s %d"," value",2415927893);
printf("%s",buff);
}
output:
value -1879039403
It's because the integer 2415927893 can't represented by any integer type on your system and you have signed overflow in your program.
The exact type of integer literal depends on how big the number is. C11 defines that an integer literal can be of int or long int or long long int, depending on which one fits first in that order.
6.4.4.1 Integer constants
The type of an integer constant is the first of the corresponding list
in which its value can be represented.
Turn on the compiler warnings.
On my system, gcc warns about it when I compile youre code with:
gcc -std=c11 -Wall -pedantic t.c
t.c:4:1: warning: return type defaults to ‘int’ [enabled by default]
t.c: In function ‘main’:
t.c:9:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long long int’ [-Wformat]
t.c:9:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long long int’ [-Wformat]
The literal 2415927893 is interpreded as an int. As it is larger than INT_MAX on your machine, you get an overflow.
To avoid this, you may interpret it as an unsigned int:
snprintf(buff,256,"%s %u"," value",2415927893U);
Or as long long:
snprintf(buff,256,"%s %lld"," value",2415927893ll);
Related
In the following example, I'm trying to scan the value of boolean type of variable. When I compile in GCC, I get following warning,
warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘_Bool *’ [-Wformat=]
scanf("%d",&b);
code:
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool b;
scanf("%d",&b);
printf("%d\n",b);
}
My question is, Is there any format specifier of bool in C?
There is no format specifier for the bool type in C.
For printf, you can rely on the implicit promotion to int, and use %d as the specified formatter.
For scanf, you ought to read it into an int, and convert appropriately. Again, using %d.
There is no specifier in C for bool.
You should typecast it in printf() to avoid warnings if you want.
But there is no dedicated format specifier for represent bool type.
Try below to avoid scanf() warning:
scanf("%d",(int*)&b)
I am using the mingw-w64 (x64) fork of minGW as prepared on nuwen.net. This is from the 7.1 version of gcc :
gcc --version
gcc (GCC) 7.1.0
I am compiling this program:
#include <stdio.h>
int main(void)
{
size_t a = 100;
printf("a=%lu\n",a);
printf("a=%llu\n",a);
printf("a=%zu\n",a);
printf("a=%I64u\n",a);
}
with warnings and c11 standard:
gcc -Wall -Wextra -Wpedantic -std=c11 test_size_t.c
and I get these warnings:
test_size_t.c: In function 'main':
test_size_t.c:6:14: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t {aka long long unsigned int}' [-Wformat=]
printf("a=%lu\n",a);
~~^
%I64u
test_size_t.c:6:14: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t {aka long long unsigned int}' [-Wformat=]
printf("a=%lu\n",a);
~~^
%I64u
test_size_t.c:7:14: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("a=%llu\n",a);
^
test_size_t.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%llu\n",a);
^~~~~~~~~~
test_size_t.c:7:14: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("a=%llu\n",a);
^
test_size_t.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%llu\n",a);
^~~~~~~~~~
test_size_t.c:8:13: warning: unknown conversion type character 'z' in format [-Wformat=]
printf("a=%zu\n",a);
^
test_size_t.c:8:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%zu\n",a);
^~~~~~~~~
test_size_t.c:8:13: warning: unknown conversion type character 'z' in format [-Wformat=]
printf("a=%zu\n",a);
^
test_size_t.c:8:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%zu\n",a);
^~~~~~~~~
test_size_t.c:9:9: warning: ISO C does not support the 'I64' ms_printf length modifier [-Wformat=]
printf("a=%I64u\n",a);
^~~~~~~~~~~
test_size_t.c:9:9: warning: ISO C does not support the 'I64' ms_printf length modifier [-Wformat=]
I would like to printf a size_t without warning but don't know the correct format specifier in this situation.
The problem is not the compiler but the C library. MinGW uses Microsoft's "Visual C Runtime" (msvcrt) which only conforms to c89 and it doesn't support the z format specifier.
Here's what you can do to safely print a size_t when using MinGW:
#include <inttypes.h>
#include <stdio.h>
#ifdef _WIN32
# ifdef _WIN64
# define PRI_SIZET PRIu64
# else
# define PRI_SIZET PRIu32
# endif
#else
# define PRI_SIZET "zu"
#endif
int main(void)
{
size_t mySize = 24;
printf("%" PRI_SIZET "\n", mySize);
}
On win64, you would get a warning with this code, because PRIu64 expands to the msvcrt-specific I64u format specifier. But you can silence this warning with the GCC flag -Wno-pedantic-ms-format.
Note that you need a similar trick for long long (here using PRIu64 on both 32bit and 64bit windows) because msvcrt doesn't know ll either.
edit: as pointed out by #M.M in a comment, you can instead link MinGW-provided alternative stdio functions that support C11 with #define __USE_MINGW_ANSI_STDIO 1. I prefer not to link extra code if I can get around the peculiarities of msvcrt, but that's of course a matter of taste.
The alternative solution as mentioned in comments is to toss in the __USE_MINGW_ANSI_STDIO compiler switch:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
int main(void)
{
size_t a = 100;
printf("a=%lu\n",a);
printf("a=%llu\n",a);
printf("a=%zu\n",a);
printf("a=%I64u\n",a);
}
This makes the code compile as expected and gcc now gives the appropriate warnings:
warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t' [-Wformat=]
warning: ISO C does not support the 'I' printf flag [-Wformat=]
warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'size_t' [-Wformat=]
Alternatively you can define the macro on command line with -D__USE_MINGW_ANSI_STDIO=1
PRIuPTR trick works (Cross platform format string for variables of type size_t?):
#include <stdio.h>
#include <inttypes.h>
int main()
{
size_t a = (size_t)(1024ULL * 1024 * 1024 * 1024 + 13);
printf("a = %" PRIuPTR "\n", a);
printf("sizeof(size_t) = %" PRIuPTR "\n", sizeof(size_t));
printf("sizeof(uintptr_t) = %" PRIuPTR "\n", sizeof(uintptr_t));
return 0;
}
Output x86:
a = 13
sizeof(size_t) = 4
sizeof(uintptr_t) = 4
Output x64:
a = 1099511627789
sizeof(size_t) = 8
sizeof(uintptr_t) = 8
According to the answers in this question, a literal like L"test" has type wchar_t[5]. But the following code with GCC seems to say something different:
int main()
{
struct Test{char x;} s;
s="Test"; // ok, char* as expected
s=L"Test"; // ??? I'd expect wchar_t*
return 0;
}
Here's how I compile it (gcc 5.2, but same results are with 4.5 and 4.8):
$ gcc test.c -o test -std=c99
test.c: In function ‘main’:
test.c:4:6: error: incompatible types when assigning to type ‘struct Test’ from type ‘char *’
s="Test"; // ok, char* as expected
^
test.c:5:6: error: incompatible types when assigning to type ‘struct Test’ from type ‘long int *’
s=L"Test"; // ??? I'd expect wchar_t*
^
Apparently, instead of the expected array of wchar_t I get array of long int. What's wrong here?
The type wchar_t is not a fundamental type, like char. It is an implementation-defined synonym of an integer type1.
1 (Quoted from: ISO/IEC 9899:201x 7.19 Common definitions 2.)
wchar_t which is an integer type whose range of values can represent distinct codes for all
members of the largest extended character set specified among the supported locales;
I am trying to use the strtoul function, but as shown below it is returning an unexpected value (adding ff's in the beginning):
#include <stdio.h>
#include <string.h>
#include <limits.h>
main() {
unsigned long temp ;
char *err;
temp = strtoul("3334444444",&err,10);
if (temp > UINT_MAX) {
printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
}else
printf("%lx %x\n",temp,3334444444);
}
$./a.out
ffffffffc6bf959c c6bf959c ffffffff
The above output corresponds to the if part being true, though I expect the else part to get executed here. Can anyone please explain why strtoul is behaving like this? Why does it return ffffffffc6bf959c rather than just c6bf959c? If I use "333444444" (i.e. just one 4 less) rather than "3334444444" in the above code, then I get the correct output (i.e. 13dff55c 13dff55c) corresponding to the else part.
Note : As pointed by melpomene in his reply below, stdlib.h header file should have been included and that will resolve the issue. Can anyone please let me know what is being done by the program by assuming the incorrect return type (int in this case) during compile time which can't be undone (or atleast it is not getting undone in this case) even after knowing the correct return type (unsigned long in this case) during link time ? In short, i want to know how c6bf959c is getting converted to ffffffffc6bf959c because of prototype not provided.
Compiling your code with gcc with warnings enabled gives:
try.c:5:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main() {
^~~~
try.c:5:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
try.c: In function ‘main’:
try.c:8:12: warning: implicit declaration of function ‘strtoul’ [-Wimplicit-function-declaration]
temp = strtoul("3334444444",&err,10);
^~~~~~~
try.c:8:5: warning: nested extern declaration of ‘strtoul’ [-Wnested-externs]
temp = strtoul("3334444444",&err,10);
^~~~
try.c:10:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
^
try.c:12:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
printf("%lx %x\n",temp,3334444444);
^
The main problem is implicit declaration of function ‘strtoul’, indicating that the function is not declared (and thus assumed to return int) because you forgot to #include <stdlib.h>. Adding the missing #include fixes the value of temp.
But you should also have a look at the warnings reported for printf and fix those.
In the code below mac_str is char pointer and mac is a uint8_t array:
sscanf(mac_str,"%x:%x:%x:%x:%x:%x",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);
When I try the above code it gives me a warning:
warning: format ‘%x’ expects argument of type ‘unsigned int *’, but argument 8 has type ‘uint8_t *’ [-Wformat]
but I saw in some code they specified
sscanf(str,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);
which doesn't give any warning but both are working the same.
What's the need of using hhx instead of just x?
&mac[0] is a pointer to an unsigned char.1 %hhx means the corresponding arguments points to an unsigned char. Use square pegs for square holes: the conversion specifiers in the format string must match the argument types.
1 Actually, &mac[0] is a pointer to a uint8_t, and %hhx is still wrong for uint8_t. It “works” in many implementations because uint8_t is the same as unsigned char in many implementations. But the proper format is "%" SCNx8, as in:
#include <inttypes.h>
…
scanf(mac_str, "%" SCNx8 "… rest of format string", &mac[0], … rest of arguments);
hh is a length modifier that specifies the destination type of the argument. The default for conversion format specifier x is unsigned int*. With hh, it becomes unsigned char* or signed char*.
Refer to the table herein for more details.
hhx converts input to unsigned char, while x converts to unsigned int. And since uint8_t is typedef to unsigned char, hhx fixes warning.