Printing hex integer by casting to char* and using "%s" in sprintf - c

I'm reading in two 32 bit registers and trying to put it inside a string buffer using the following:
sprintf (buffer, "%s-%s", ((char*)(in32(REGISTER1))) , (char*)(in32(REGISTER2)));
Can the hex value read in from the registers not be typecast as a pointer to a char and be printed into the buffer as above?

As craig65535 implies in a comment above, the problem is most likely with this phrase:
the hex value read in from the registers
I doubt that you're reading in a hex value; rather, you're reading in an integer. If you want to store a hex representation of that integer in a string, you'd use the %X format specifier:
sprintf (buffer, "%08X-%08X", in32(REGISTER1), in32(REGISTER2));
(The 8 means "use a width of eight characters"; the 0 means "left-pad with zeroes if the value is such that the width is less than eight".)
The only way you could validly cast to char * is if the integer value in the register is actually a pointer to some memory location where you've stored a string; but that is clearly not the case here.

sprintf(buffer, "%08x-%08x", REGISTER1, REGISTER2);
-- that's assuming you want the register addresses in your buffer. If your intention is to read the contents of the registers, adjust accordingly. The point though is you cannot simply call a number a char* and get the number out of it, but sprintf() (and all printf-like functions) can convert value bases for you.

As the others answers suggest, you can convert your integer to a string hex representation with sprintf using %X.
But as you didn't said what compiler you use or what the length of integer or long is, you could get unexpected results.
On a 16bit controller sprintf (buffer, "%08X-%08X", in32(REGISTER1),in32(REGISTER2)); would fail.
This should work on the most plattforms, as sprintf assume long values as arguments, and the arguments are always casted to longs.
sprintf (buffer, "%08lX-%08lX", (long)in32(REGISTER1), (long)in32(REGISTER2));

Related

directly cast a char *nib as int hex

in pure and portable c.
So I am having trouble casting what has to be a variable, from a variable. char *nib to int hex. The idea being I had a char *nib ="ab"; or "0xab" or anything that directly represents two characters as a char *. then casting it as a integer. and writing it to a file to get a one to one write. so I start with char *nib="0xab"; then I write it as a int presumably, and to a hexdump or edit and the result is just ab.
I've been able to do this as a constant directly declaring... but the nib is always static.
this has to be a one to one starting with a two char string or nib. Not converting anything, purly casting.
So can you write it directly to a file without converting it? three look up tables seems like a bit much for a value what has the name length
There is no way to cast 2 characters (2 bytes) into one byte because cast does not change binary representation of the value.
The closest you can get to casting string that looks like hex to some value that will show something similar is use 0-15 characters via escape sequence like char* nib = "\x0A\x0B" and cast ( *((short*)nib)) that to 2-byte value (0x0A0B in this case) and store that to a file (I'm not sure if there is portable integer type of 2 bytes - short often is 2 bytes wide but does not have to be 2 bytes). Unfortunately I don't think there is a portable way to store 2 byte integer value to a file as different architectures may have different byte order.
Writing string value character by character is likely safest approach. Or convert string to int a usual way and use your own read/write code for integers to ensure portability.

Variable affected by type conversion

I have always thought that when a variable is typecast, a copy of it results and any changes affect that temporary variable. But, the screenshot below indicates otherwise. Apparently, the original variable is what changes. Why? I am curious because I have never seen anything similar.
sprintf nul-terminates the string it outputs into the provided buffer. As the %010lu format specifier requests a number padded to be at least 10 digits long, you are consistently overflowing crc_buf and triggering UB. In your specific case, the least significant byte of crc gets trampled.
Make crc_buf 11 characters or more, and use snprintf instead of sprintf to catch this class of errors. For maximal portability, you could also use the PRIu32 format macro instead of casting:
snprintf(crc_buf, sizeof crc_buf, "%10" PRIu32, crc);

uint64 to string in C

I have a uint64 value that I want to convert into a string because it has to be inserted as the payload of an HTTP POST request.
I've already tried many solutions (ltoa, this solution ) but my problem still remains.
My function is the following:
void check2(char* fingerprint, guint64 s_id) {
//stuff
char poststr[400] = "action=CheckFingerprint&sessionid=";
//convert s_id to, for example, char* myChar
strcat(poststr, myChar);
}
I want to convert s_id to char*. I've tried:
1) char ses[8]; ltoa(s_id,ses,10) but I have a segmentation fault;
2) char *buf; sprintf(buf, "%" PRIu64, s_id);
I'm working on a APIs, so I have seen that when this guint64 variable is printed, it has the following form:
JANUS_LOG(LOG_INFO, "Creating new session: %"SCNu64"\n", session_id);
sprintf is the right way to go with an unsigned 64 bit format specifier.
You'll need to allocate enough space for 16 hex digits and the null byte. Here I've allocated 20 bytes to accommodate a leading 0x as well and then I rounded it up to 20 for no good reason other than it feels better than 19.
char foo[20];
sprintf(foo, "0x%016" PRIx64, (uint64_t)numberToConvert);
will print the number in hex with leading 0x and leading zeros padded up to 16. You do not need the cast if numberToConvert is already a uint64_t
i have a uint64 value that i want to convert into char* because of it have to be inserted as payload of an HTTP POST request.
What you have is a fundamental misunderstanding.
To insert a text representation of your value into a document, you need to convert it to a sequence of characters, which is quite a different thing from a pointer to a character (char *). One of your options, which seems to be what you're really after, is to convert the value to a sequence of characters in the form of a C string -- that is, a null-terminated array of characters. You would then have or be able to obtain a pointer to the first character in the sequence.
That explains what's wrong with this attempted solution:
char *buf;
sprintf(buf, "%" PRIu64, s_id);
You are trying to write the string representation of your number into the array pointed-to by buf, but it doesn't point to one. Not having been initialized or assigned, its value is indeterminate.
Even if you your buf pointed to an array, it is essential that the array be long enough to accommodate all the digits of the value's decimal representation, plus a terminator. That's probably what's wrong with your other attempt:
char ses[8]; ltoa(s_id,ses,10)
An unsigned, 64-bit binary number may require up to 20 decimal digits, plus you need space for a terminator. The array you're providing is not nearly large enough, unless you can be confident that the actual values you're going to write will not exceed 9,999,999 (which is well within the range of a 32-bit integer).

C Control Strings?

I know that in other languages such as Java when I use System.out.println(); and I put a variable inside of it like an int that holds the number 22 it will print 22 to the console.
In C if I do the same thing with printf(); I need to specify the type in the string such as printf("%d", n); I also know that Java has its own printf function.
What I am trying to get at here is how the C control String works compared to other languages such as Java where you don't have to provide the type identifier in the System.out.println(); and it automatically recognizes the variable is an int.
Is this part of C's way of efficiency and does it not actually check the type and rely's on the programmer to understand the type they are providing?
In fact, printf is neither efficient nor type-safe way of writing data.
There is a performance penalty because format string is parsed at compile time and type specific actions are chosen at run time as well, whereas in C++ and Java it can be done at compile time. Moreover, variadic arguments are forced to be passed on the stack, that is less efficient than passing them in registers.
And what is even more important is that printf is not type-safe. It is possible to pass any number of parameters of any types to printf, ignoring format string prescriptions. Of course, it can easily trigger undefined behavior.
The only reason for such behavior is that there is no function overloading in C.
On the other hand, it's not that bad. First, most of the compilers parse format string and issue a warning if it isn't consistent with parameters passed to printf. Second, aforementioned performance penalty is in fact negligible compared to the cost of formatting and printing text after types have been deduced.
Both C's predefined data types (integers, characters, etc.) as well as user defined types carry no type information with them at run-time. Thus if you use a 4 byte integer in your code, it occupies only 4 bytes in memory (disregarding any padding needed for alignment). This is great for efficiency reasons, but it means that functions that handle multiple data types (like printf) need to be told via the format/control string what the types of the arguments are.
So when printf receives a format string of "%d %f" it knows that the type of the first non-format argument is integer and the second argument is of type float.
By passing control characters in printf() we tell the compiler how to allocate the memory and what is the range of the data that we wanna to print.
Control strings are also known as format specifiers. They are used in formatted input and output operations of the data. Remember, format specifiers are used for formatting the data, for example, in printf() and scanf().
Control strings in scanf() are used to transfer the data to the processor's memory in a formatted way, whereas printf () transfers the data to the output device e.g. monitor screen in a formatted way.
Some common Format Specifierss are listed below:
________________________________________________________________
FORMAT SPECIFIER :: DESCRIPTION
________________________________________________________________
%c Character
%d Signed Integer
%e or %E Scientific notation
%f Floating point
%g or %G. Similar as %e or %E
%hi. Signed Integer
%hu Unsigned Integer(Short)
%i Signed Integer
%l or %ld or %li Signed Integer
%lf Floating point
%Lf Floating point
%lu Unsigned integer
%lli, %lld Signed long long int
%llu. unsigned long long int
%o. Octal representation of Integer.
%p Address of pointer to void void *
void *
%s String char *
%u Unsigned int
Unsigned short int
%n Prints nothing
%% Prints % character
%o Octal representation
%p Address of pointer to void void *
void *
%s String char *
%u Unsigned Integer
%x or %X Hexadecimal representation of
Unsigned Int.
%n Prints nothing
%% Prints % character
________________________________________________________________

Separated integers with comma delimiters and sscanf

I need help with sscanf.
I have a data file. I read it line by line.
One line is look like this: 23,13,45;
I want to read the integers.
I try this code:
unsigned char a,b,c;
sscanf(line,"%d,%d,%d;",&a,&b,&c);
But this is not working, only the first number read, the others is 0.
This is because %d expects a pointer to a 4-byte integer, and you are passing a pointer to a 1-byte char. Because variables a, b and c are stored in the order of decreasing memory addresses, sscanf first fills a with 23, at the same time filling 3 other bytes of stack memory with zeros (this is a memory violation, BTW). Then it fills b with 13, also filling a and two other bytes with zeros. In the end it fills c with 45, also filling a and b and one other byte with zeros. This way you end up with zeros in both b and a, and an expected value only in c.
Of course this is only one possible scenario of what can happen, as it depends on the architecture and compiler.
A proper way to read 4 integers would be to use int instead of unsigned char, or change the format specifier.
Correct format specifier for unsigned char is %hhu.
Other than that I don't see any problem as long as line does contain the string in the format you expect.

Resources