Issues with sprintf - c

I have been trying to use sprintf to add " to the start and end of a integer, however when i use more than 10 digits the program returns the wrong number:
int data2 = 12345678910;
char data3[2];
sprintf(data3,"\"%i\"", data2);
send(data3);
The send function outputs the integer to the screen.
The result i am getting back is :
"-108508098"
The send function works as i use it elsewhere and it does what it is suppose to.

Before your edit, your issue is not only with sprintf (which BTW you should not use, prefer snprintf), it is with integral numbers in C (they have a limited amount of bits, e.g. 64 bits at most on my Linux desktop....; read wikipages on computer number format & C data types).
Your use of sprintf is completely wrong (you've got a buffer overflow, which is an undefined behavior). You should code:
char buffer[32];
snprintf(buffer, sizeof(buffer), "%i", data2);
sendsomewhere(buffer);
Notice that on POSIX send needs 4 arguments. You should rename your function to sendsomewhere
You should read more about <stdint.h> and <limits.h>
You probably want to use bignums (or at least int64_t or perhaps long long to represent numbers like 12345678910). Don't reinvent bignums (they are difficult to implement efficiently). Use some library like gmplib
If 64 bits are enough for you (so if your numbers would always be between -263 i.e. −9223372036854775808 and 263-1 i.e. 9223372036854775807), consider using long long (or unsigned long long) numbers of C99 or C11:
long long data2 = 12345678910;
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lld", data2);
sendsomewhere(buffer);
If 64 bits are not enough, you should use bigints (but some recent compilers might provide some _int128_t type for 128-bits ints)
Don't forget to enable all the warnings & debug info when compiling (e.g. with gcc -Wall -Wextra -g), then learn how to use the debugger (e.g. gdb)

data2 is overflown by the value to which you have initialized it to.
data3 should be able to hold atleast 11 bytes if data2 is of int datatype (+1 for NULL termination), for which you have allocated only 2 bytes.
Here is an example code snippet:
#include <stdio.h>
int main(void)
{
unsigned long long data2 = 12345678910;
char data3[32];
snprintf(data3, sizeof(data3), "\"%llu\"", data2);
printf("%s\n", data3);
return 0;
}

Related

Problem with using scanf function under stm32

I've came across on some interesting thing during use of sscanf() for STM32F437:
uint8_t var;
st = sscanf(&line[off], "%x", &var);
st = sscanf(&line[off], "%hhx", &var);
When I'm trying to compile first line I get suggestion from gcc to use "%hhx" instead of "%x". But when I changed this line to the second one - suggestion from gcc disappeared, but the result of scanning is wrong.
When &line[off] points to following string: 52 then the first scanf(..."%x"...) is working correctly giving 0x52, but the second scanf(..."%hhx"...) produces result 0x34.
Seems like scanf("..."%hhx"...") interpretes 52 as a decimal value 52 and then converts it to hexadecimal value 0x34.
I am using arm-none-eabi-gcc version 9.2.0.
Did I miss something or this is some bug in scanf()?
You are linking against what is commonly refereed as "newlib-nano". Nano version of newlib comes with limited support from the standard library - it doesn't support all C99 length modifiers, like ll or hh in both printf and scanf.
The solution is to link against full implementation of newlib, so remove -specs=nano.specs or similar from the linking options, or don't use hh length modifier when compiling with newlib-nano or use other method of converting a string to an integer.
%x without a prefix before the x means scanf is expecting a pointer to unsigned int
%hh is used for signed char or unsigned char.
%hhx is used for signed char or unsigned char in hex format.
"%"SCNu8 is used for scanning uint8_t.
"%"SCNx8 is used for uint8_t in hex format.
uint8_t is most likely 100% equivalent to unsigned char on any system.
This means that here "%x", &var you lie to the compiler and (assuming 32 bit CPU) you tell it "go ahead and read 32 bit large integer), then pass a memory address where only 8 bits of valid data are stored. This is undefined behavior and anything can happen.
Speculating about why undefined behavior bugs manifest themselves in a certain way for your specific system is rather meaningless.
Instead, do this:
#include <inttypes.h>
uint8_t var;
st = sscanf(&line[off], "%"SCNx8, &var);
Please note that sscanf is a terribly slow and dangerous function and should not be used on embedded systems. Always use strtoul instead.

C printf of an integer with %lu produces large number

I know that is bad practice to print an integer with %lu which is a unsigned long. In a project i was working on i got a large number when trying to print 11 with %lu in the snprint format.(old code) I am using gcc 4.9.3.
This code below i thought would produce the wrong number since snprintf is told to read more than the 4 bytes occupied. Its doesnt though. Works perfectly. It reads everything correctly. Either it does not go past the 4 bytes in to the unknown or the extra 4 bytes in the long are fully of zeros when it gets promoted to long from int.
I am wondering out of curiosity is when does printf print the wrong number? What conditions does it need produce a wrong big number? There has to be garbage in the upper 4 bytes but it seems like it does not set that garbage for me.
I read the answers here but the code worked for me. I know its a different compiler.
Printing int type with %lu - C+XINU
#include<inttypes.h>
#include<stdio.h>
int main(void){
uint32_t number1 = 11;
char sentence[40];
snprintf(sentence,40,"Small number :%lu , Big number:%lu \n",number1,285212672);
printf(sentence);
}
On OP's machine, uint32_t, unsigned long and int appear to be the same size #R Sahu. OP's code is not portable and may produce incorrect output on another machine.
when does printf print the wrong number?
Use the matching printf() specifier for truly portable code. Using mis-matched specifiers may print the wrong number.
The output string may be well over 40 characters. Better to use a generous or right-sized buffer.
#include <inttypes.h>
#include <stdio.h>
int main(void){
uint32_t number1 = 11;
// char sentence[40];
char sentence[80];
snprintf(sentence, sizeof sentence,
"Small number :%" PRIu32 " , Big number:%d \n",
number1, 285212672);
// printf(sentence); // Best not to print a string using the printf() format parameter
fputs(sentence, stdout);
}

why pointer variable not showing 100 digits?

aim: i had a requirement for accuracy i need 100 digits to be displayed or atleast 50 digits
try 1: first i had used integer variable then it displayed only 10 digits
try 2: with the help of my friend i used pointers concept it successfully had input 50 to 100 digits but pointer variable display only 10 digits
the program i had written was
#include <stdio.h>
#include <string.h>
main()
{
int *p;
p=(int*)malloc(100*sizeof(int));
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
printf("%d",*p);
}
on executing the above procedure i'm getting a garbage value
thanks in advance
You need to use a bignum (arbitrary precision big numbers) library, since native int or long have a precision limited by the C implementation - ie the hardware (often 32 or 64 bits; see also <stdint.h> header and int32_t & int64_t types). I suggest using GMPlib; you need to be fluent in C to use such libraries. Read documentation of GMLib.
Don't try to code bignumber arithmetic yourself. You'll use inefficient algorithms. Efficient algorithms for bignums are difficult to understand and to invent. You can still get a PhD on that. So use some existing bignum library.
So you might code something like the following to multiply your bignum by 137 and print the result
mpz_t bign;
mpz_t bigr;
// initialize bign from a literal string
mpz_init_set_str (bign,
"12345678901234567890123456789012345678901234567890"
"12345678901234567890123456789012345678901234567890",
10);
// initialize bigr
mpz_init(bigr);
/// compute bigr = bign * 137 (137 is a long, not a bignum)
mpz_mul_si(bigr, bign, 137L);
/// print bigr on stdout in base 10
mpz_out_str (stdout, 10, bigr);
/// clear all the numbers
mpz_clear(bign);
mpz_clear(bigr);
On a Linux system with GMP installed, you could compile such a code (in yoursource.c) using:
gcc -Wall -Wextra -g yoursource.c -lgmp -o yourprog
On other systems you might need some -I and -L arguments to gcc. When you have debugged your program, ask the compiler to optimize it with -O2
Notice that some languages (Common Lisp, Scheme, Python) have built-in bignums.
BTW, your main function is incorrectly defined. It should be defined as int main(int argc, char**argv) ...
To answer the first part, a single signed integer (assuming 32 bits) can take values between -2,147,483,648 and +2,147,483,647
This is where your ten digits comes from.
Depending on your compiler, you may have unsigned long long available (64 bits) but that still only offers you a maximum or 0..18,446,744,073,709,551,615 (20 digits)
To handle 100-digit numbers will require some jiggery-pokery!
int * p = malloc(100*sizeof(int));
Allocates memory for an array of 100 int.
*p= ....
In fact is the same as
p[0]=...
So this
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
assigns to an int.
An int may hold not more then a 32 bits (less on some platforms). The largest 32bit (positive) integer is 2147483647.
C is a language close to the hardware. So you need to understand the storage capabilities and limitations of its data types.
An int on a PC is only able to store 32 bit or 64 bit values, depending on your hardware and OS version.
Yes, you can implement routines for handling larger value, and using a linked list of digits is one way do it.
You can't store such a long digit in an int variable or a pointer which is pointing to type int.
If int is of 32 bit, the range is [−2147483647,+2147483647]. C data types
To store the large value you can use a char pointer and initialized it with the string constant.
For example:
#include <stdio.h>
#include <stdlib.h>
main()
{
char *p = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
printf("%s\n",p);
}

why pointer variable not showing 100 digits? [duplicate]

aim: i had a requirement for accuracy i need 100 digits to be displayed or atleast 50 digits
try 1: first i had used integer variable then it displayed only 10 digits
try 2: with the help of my friend i used pointers concept it successfully had input 50 to 100 digits but pointer variable display only 10 digits
the program i had written was
#include <stdio.h>
#include <string.h>
main()
{
int *p;
p=(int*)malloc(100*sizeof(int));
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
printf("%d",*p);
}
on executing the above procedure i'm getting a garbage value
thanks in advance
You need to use a bignum (arbitrary precision big numbers) library, since native int or long have a precision limited by the C implementation - ie the hardware (often 32 or 64 bits; see also <stdint.h> header and int32_t & int64_t types). I suggest using GMPlib; you need to be fluent in C to use such libraries. Read documentation of GMLib.
Don't try to code bignumber arithmetic yourself. You'll use inefficient algorithms. Efficient algorithms for bignums are difficult to understand and to invent. You can still get a PhD on that. So use some existing bignum library.
So you might code something like the following to multiply your bignum by 137 and print the result
mpz_t bign;
mpz_t bigr;
// initialize bign from a literal string
mpz_init_set_str (bign,
"12345678901234567890123456789012345678901234567890"
"12345678901234567890123456789012345678901234567890",
10);
// initialize bigr
mpz_init(bigr);
/// compute bigr = bign * 137 (137 is a long, not a bignum)
mpz_mul_si(bigr, bign, 137L);
/// print bigr on stdout in base 10
mpz_out_str (stdout, 10, bigr);
/// clear all the numbers
mpz_clear(bign);
mpz_clear(bigr);
On a Linux system with GMP installed, you could compile such a code (in yoursource.c) using:
gcc -Wall -Wextra -g yoursource.c -lgmp -o yourprog
On other systems you might need some -I and -L arguments to gcc. When you have debugged your program, ask the compiler to optimize it with -O2
Notice that some languages (Common Lisp, Scheme, Python) have built-in bignums.
BTW, your main function is incorrectly defined. It should be defined as int main(int argc, char**argv) ...
To answer the first part, a single signed integer (assuming 32 bits) can take values between -2,147,483,648 and +2,147,483,647
This is where your ten digits comes from.
Depending on your compiler, you may have unsigned long long available (64 bits) but that still only offers you a maximum or 0..18,446,744,073,709,551,615 (20 digits)
To handle 100-digit numbers will require some jiggery-pokery!
int * p = malloc(100*sizeof(int));
Allocates memory for an array of 100 int.
*p= ....
In fact is the same as
p[0]=...
So this
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
assigns to an int.
An int may hold not more then a 32 bits (less on some platforms). The largest 32bit (positive) integer is 2147483647.
C is a language close to the hardware. So you need to understand the storage capabilities and limitations of its data types.
An int on a PC is only able to store 32 bit or 64 bit values, depending on your hardware and OS version.
Yes, you can implement routines for handling larger value, and using a linked list of digits is one way do it.
You can't store such a long digit in an int variable or a pointer which is pointing to type int.
If int is of 32 bit, the range is [−2147483647,+2147483647]. C data types
To store the large value you can use a char pointer and initialized it with the string constant.
For example:
#include <stdio.h>
#include <stdlib.h>
main()
{
char *p = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
printf("%s\n",p);
}

C convert hex to decimal format

Compiling on linux using gcc.
I would like to convert this to hex. 10 which would be a.
I have managed to do this will the code below.
unsigned int index = 10;
char index_buff[5] = {0};
sprintf(index_buff, "0x%x", index);
data_t.un32Index = port_buff;
However, the problem is that I need to assign it to a structure
and the element I need to assign to is an unsigned int type.
This works however:
data_t.un32index = 0xa;
However, my sample code doesn't work as it thinks I am trying to convert
from an string to a unsigned int.
I have tried this, but this also failed
data_t.un32index = (unsigned int) *index_buff;
Many thanks for any advice,
Huh? The decimal/hex doesn't matter if you have the value in a variable. Just do
data_t.un32index = index;
Decimal and hex are just notation when printing numbers so humans can read them.
For a C (or C++, or Java, or any of a number of languages where these types are "primitives" with semantics closely matching those of machine registers) integer variable, the value it holds can never be said to "be in hex".
The value is held in binary (in all typical modern electronic computers, which are digital and binary in nature) in the memory or register backing the variable, and you can then generate various string representations, which is when you need to pick a base to use.
I agree with the previous answers, but I thought I'd share code that actually converts a hex string to an unsigned integer just to show how it's done:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *hex_value_string = "deadbeef";
unsigned int out;
sscanf(hex_value_string, "%x", &out);
printf("%o %o\n", out, 0xdeadbeef);
printf("%x %x\n", out, 0xdeadbeef);
return 0;
}
Gives this when executed:
emil#lanfear /home/emil/dev $ ./hex
33653337357 33653337357
deadbeef deadbeef
However, my sample code doesn't work as it thinks I am trying to convert from an string to a unsigned int.
This is because when you write the following:
data_t.un32index = index_buff;
you do have a type mismatch. You are trying to assign a character array index_buff to an unsigned int i.e. data_t.un32index.
You should be able to assign the index as suggested directly to data_t.un32index.

Resources