What is the meaning of the format control specifier %016I64X in sprintf_s - string-formatting

What is the meaning of the format control specifier "%S\%016I64X%S" in this sprintf_s command ?
As far as I know, it defines a string which converts numbers to unsigned 64 bit integer in Hexadecimal format. I would like to know whether I am right ? Please help me..
char lFileName[MAX_PATH];
sprintf_s( lFileName, MAX_PATH, "%S\\%016I64X%S", mSavePath.GetBuffer(),aBuffer->GetTimestamp(), lExt );

First, it looks like a Visual C++ usage of
int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
The format consists of multiple directives: "%S", "\\", "%016I64X", "%S".
"%S" "When used with printf functions, specifies a wide-character string; ..." more
"\\" is simply a \.
"%016I64X" is an X format specifier of hexadecimal output. 0 to indicate zero-filling as needed. 16 to indicate the minimum output length. I64 is a windows specific modifier indicating the expected integer is of windows specific type unsigned __int64. more
You are on the right track with "unsigned 64 bit integer".

Related

Writing and reading a binary file in c

I am trying to write an integer to a binary file and then read the same thing. However, my program reads a different number than the one that was written. What am I doing wrong?
unsigned short int numToWrite = 2079;
// Write to output
FILE *write_ptr;
write_ptr = fopen("test.bin","wb"); // w for write, b for binary
printf("numToWrite: %d\n", *(&numToWrite));
fwrite(&numToWrite, sizeof(unsigned short int), 1, write_ptr); // write 10 bytes from our buffer
fclose(write_ptr);
// Read the binary file
FILE *read_ptr = fopen(filename, "rb");
if (!read_ptr) {
perror("fopen");
exit(EXIT_FAILURE);
}
unsigned short int* numToRead = malloc(sizeof (unsigned short int));
fread(numToRead, sizeof(unsigned short int), 1, read_ptr);
printf("numToRead: %d\n", *numToRead);
free(numToRead);
fclose(read_ptr);
The output is this:
numToWrite: 2079
numToRead: 26964
man printf
Length modifier
h - A following integer conversion corresponds to a short or unsigned short argument, ...
Conversion specifiers
d,i - The int argument is converted to signed decimal notation.
Format of the format string
...Each conversion specification is introduced by the character %, and ends with a conversion specifier. In between there may be (in this order) zero or more flags, an optional minimum field width, an optional precision and an optional length modifier.
You're using unsigned short int, but that's not what you're telling to printf.
Hence, your expectations are not fulfilled.
A few things that are going on:
'printf' does not have any binary format specifier, so you would have to do it manually.
You need to take a deep dive in data types and their ranges, so I recommend using this source: Microsoft Data Type Ranges. It says C++, it is irrelevant since it gives you a good idea of the ranges.
I know this is isn't you're entire code, but just understand there are somethings from what I'm seeing that is not defined, such as 'filename'.
In case someone mentions atoi() and itoa(), keep this in mind, theoretically you could use atoi() and itoa(), however just be mindful that atoi() and itoa() is a non-standard function which is supported by some compilers.
Lastly, why are you using 'unsigned short int', '*(&numToWrite)' and is there anymore from the program that you can show us?

How printf() function knows the type of its arguments

Consider the following program,
#include <stdio.h>
int main()
{
char a = 130;
unsigned char b = 130;
printf("a = %d\nb = %d\n",a,b);
return 0;
}
This program will show the following output.
a = -126
b = 130
My question is how printf() function comes to know the type of a is signed and type of b is unsigned to show result like above?
printf() doesn't know the types, that's why you have to give a correct format string. The prototype for printf() looks like this:
int printf(const char * restrict format, ...);
So, the only argument with a known type is the first one, the format string.
This also means that any argument passed after that is subject to default argument promotion -- strongly simplified, read it as any integer will be converted to at least int -- or ask google about the term to learn each and every detail ;)
In your example, you have implementation defined behavior:
char a = 130;
If your char could represent 130, that's what you would see in the output of printf(). Promoting the value to int doesn't change the value. You're getting a negative number instead, which means 130 overflowed your char. The result of overflowing a signed integer type during conversion in C is implementation defined, the value you're getting probably means that on you machine, char has 8 bits (so the maximum value is 127) and the signed integer overflow resulted in a wraparound to the negative value range. You can't rely on that behavior!
In short, the negative number is created in this line -- 130 is of type int, assigning it to char converts it and this conversion overflows.
Once your char has the value -126, passing it to printf() just converts it to int, not changing the value.
The additional arguments to printf() are formatted according to the type specifier. See here for a list of C format specifiers.
https://fr.cppreference.com/w/c/io/fprintf
It's true that one would not expect b to be printed as 130 in your example since you used the %d specifier and not %u. This surprising behavior seems to be explained here.
Format specifier for unsigned char
I hope I got your question well.
Edit: I can not comment Felix Palmen's answer on account on my low reputation. default argument promotion indeed seems to be the key here, but to me the real question here besides the overflow of a is why b is still printed as 130 despite the use of the signed specifier. It can also be explained with default argument promotion but that should be made more precise.
You need to have a look at the definition of printf statement in stdio.h. You already got the answer in comment printf just write the string pointed by format to stdout.
It's variadic function and it use vargas to get all the arguments in variable-length argument list.
You
This is from the glibc from the GNU version.
int __printf (const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (stdout, format, arg);
va_end (arg);
return done;
}
What vfprintf does?
It just writes the string pointed by format to the stream, replacing any format specifier in the same way as printf does, but using the elements in the variable argument list identified by arg instead of additional function arguments.
More information about the vfprintf
printf() does not know the data type of arguments. It works on format specifier you passed. The data type you are using is char (having range from -128 to +127) and unsigned char (having range from 0 to 255). Your output for a is overflowed after 127. So the output comes to -126.

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
________________________________________________________________

How to print a unsigned char to a human readable format in c?

I would like to print the unsigned char in this format:
0xff. How can I do so? Thanks.
printf("0x%02X", value & 0xFF);
if you want to values to always be 2 characters. also "& 0xFF" will avoid some values to be printed with a lot of "F" in the front (happens sometimes)
%x is the basic conversion specifier for printing an unsigned int (that's what an unsigned char is converted to when passed to a variadic function, such as printf()) in hexadecimal format with lowercase letters. If you want leading zeroes and at least two digits, use %02x. If, in addition, you want the 0x prefix as well, prepend the # modifier. So your format string will look like
"%#02x"
printf("0x%x\n", variable);
Visit printf documentation page for more details
%x is the format specifier you are looking for.
printf("0x%x\n",your_char);
For chars I use this
printf("0x%hhx\n",your_char);

reading hex data from file fscanf format compile time warning

I'm reading some data from a file. The format is stated tobe
ASCII text with UNIX-style
line-endings, a series of 32-bit
signed integers in hexadecimal.
e.g
08000000
I'm using fscanf to read in this data.
long data_size;
FILE *fp;
fp=fopen("test01.bin", "r"); // open for reading
if (fp==0) {cerr << "Error openeing file"<<endl; return 1;}
fscanf(fp, "%x", &data_size);
Everything runs ok with my test file but I get the compile-time warning,
warning: format ‘%x’ expects type ‘unsigned int*’, but argument 3 has type ‘long int*’
however a hex value is unsigned and is being cast to a long dose this matter? As long will take the most significant bit as notifying the sign? Or will I end up with problems? Or am I well off the mark in my understanding?
Thanks
You should support the same pointer type as the warning states, or else you will run into serious troubles if you want to port your code to other architectures (e.g: 64 bit architectures) where long has a different size than int. This is especially tricky if you are using pointers. (I once had a bug originating from exactly this problem)
Just use int data_size and you will be fine.
The problem is that %x requires an unsigned int * to read the value in, but you have a long *. <stdint.h> header provides value types with fixed length, and <inttypes.h> defines corresponding macros for use with printf, scanf, and their derivatives. I think it'll be better for you to fscanf the data into an int32_t variable using the macro provided by <inttypes.h>:
#include <inttypes.h>
...
int32_t data_size;
fscanf(fp, "%" SCNx32, &data_size);

Resources