Deep understanding _c language based on C-language sprintf function

Source: Internet
Author: User
Tags 04x control characters sprintf
printf is probably the second function that many programmers come into contact with when they start learning C (I guess the first one is main), but it's an old friend, but do you know much about this old friend? Do you know much about his twin brother sprintf? When you construct various types of data into strings, the powerful features of sprintf rarely disappoint you.
Because sprintf is almost the same as printf in usage, it's just a different destination for printing, which is printed to a string, and the latter is printed directly on the command line. This also causes sprintf to be much more useful than printf. So this article focuses on the introduction of sprintf, sometimes interspersed with the use of PRITNF.
sprintf is a variable parameter function, defined as follows:
int sprintf (char *buffer, const char *format [, argument] ...);
In addition to the first two parameter types are fixed, any number of parameters can be followed. And its essence, obviously, is on the second argument: Formatting the string.
Both printf and sprintf use a formatted string to specify the format of the string, using some format specifiers that begin with a "%" (formatted specifications) to occupy a position, and to provide the corresponding variable in the list of arguments in the back. The final function replaces the descriptor with the corresponding position variable to produce a string that the caller wants.
1. Format numeric string
One of the most common applications of sprintf is to print integers to a string, so SPRITNF can replace itoa in most situations. Such as:
Print the integer 123 into a string and save it in S.
sprintf (S, "%d", 123); Produce "123″
You can specify the width, insufficient left fill space:
sprintf (S, "%8d%8d", 123, 4567); Produced: "123 4567″
Of course, you can also align Left:
sprintf (S, "%-8d%8d", 123, 4567); Produced: "123 4567″
You can also print in 16:
sprintf (S, "%8x", 4567); lowercase 16, width to 8 positions, right aligned
sprintf (S, "%-8x", 4568); Uppercase 16, width to 8 positions, left-aligned
That way, an integer's 16 string is easy to get, but when we print the 16 feed, we usually want a equal-width format with a left complement of 0. Simply put a 0 in front of the number that represents the width.
sprintf (S, "%08x", 4567); Produced: "000011d7″
The 10-in-print printing above with "%d" can also use this left complement of 0.
Notice the problem of a symbolic extension: for example, if we want to print the memory 16 binary representation of a short integer, 1, on the Win32 platform, a shorter type occupies 2 bytes, so we naturally want to print it in 4 16 digits:
Short si =-1;
sprintf (S, "%04x", si);
Produce "ffffffff", what's going on? Because SPRITNF is a variable parameter function, in addition to the first two parameters, the following parameters are not type-safe, and the function is not able to only through a "%x" to know the original function call before the argument is pressed in the end is a 4-byte integer or a 2-byte short integer, Therefore, a unified 4-byte processing, resulting in the parameters of the stack when the symbol expansion, expanded into a 32-bit integer-1, printing when 4 position is not enough, the 32-bit integer-1 8-bit 16-digit print out. If you want to see the true nature of SI, then you should let the compiler do 0 extensions instead of symbolic extensions (when extending the binary left complement 0 instead of the complement symbol bit):
sprintf (S, "%04x", (unsigned short) SI);
It's OK. Or:
unsigned short si =-1;
sprintf (S, "%04x", si);
sprintf and printf can also print an integer string in 8, using "%o". Note that both 8 and 16 will not print a negative number, which is unsigned, in fact, a direct 16-or 8-binary representation of the internal encoding of the variable.
2. Control floating point number printing format
The printing and formatting control of floating point numbers is another common function of sprintf, floating-point number uses the format character "%f" control, the default is to keep 6 digits after decimal, for example:
sprintf (S, "%f", 3.1415926); Produce "3.141593″
But sometimes we want to control the width and scale of the print, and then we should use the "%M.NF" format where m represents the width of the print, and n indicates the number of digits after the decimal point. Like what:
sprintf (S, "%10.3f", 3.1415626); Produced: "3.142″
sprintf (S, "%-10.3f", 3.1415626); Produced: "3.142"
sprintf (S, "%.3f", 3.1415626); Do not specify the total width, resulting in: "3.142″
Pay attention to a question, you guess.
int i = 100;
sprintf (S, "%.2f", I);
What's going to happen? "100.00"? Is that right? Try it yourself, and try the following:
sprintf (S, "%.2f", (double) i);
The first one is definitely not the right result, as mentioned earlier, the caller does not know that the format controller corresponding to I is a "%f" when the parameter is pressed. The function is not aware of the execution of the stack in the year was a whole number, so the poor save integer I of the 4 bytes was use robust reporting forced as a floating-point format to explain the whole mess.
However, if someone is interested in using a floating-point number to encode manually, you can use this method to verify that the results you have manually choreographed are correct. J
Character/ascii Code Control
We know that in C/s + + language, char is also a common type of scalable, except for word length, it has no essential difference from these types of Short,int,long, but is used to represent characters and strings. (Perhaps it was time to call this type "byte," and now it's more appropriate to use byte or short to define char through typedef.)
So, using "%d" or "%x" to print a character, you can get its 10-or 16-in ASCII, which, in turn, prints an integer with "%c" to see its corresponding ASCII character. The following section prints the ASCII-code table of all visible characters to the screen (printf here), noting that "#" when combined with "%x" automatically adds a "0X" prefix for the 16 number:
for (int i = i < 127; i++) {
printf ("[%c]:%3d 0x% #04X/n", I, I, I);
}
3. Connection string
sprintf's format control string can be inserted in a variety of things, and eventually "connected to a string", naturally can connect strings, so that in many cases can replace strcat, but sprintf can connect multiple strings at one time (naturally also can be inserted in the middle of other content, In short, very flexible). Like what:
char* who = "I";
char* whom = "CSDN";
sprintf (S, '%s love%s ', who, whom); Produce: "I love CSDN." ”
Strcat can only connect strings (an array of characters ending with '/0 ' or called character Buffering, null-terminated-string), but sometimes we have two-character buffers, and they don't end with '/0 '. For example, many character arrays that are returned from Third-party library functions, which are read in the form of hardware or network transmissions, do not necessarily end with a corresponding '/0 ' after each sequence of characters. If the direct connection, whether sprintf or strcat will certainly lead to illegal memory operations, and strncat at least requires the first parameter is a null-terminated-string, then what to do? We will naturally recall the previous description you can specify the width when printing integers and floating-point numbers, as well as strings. Like what:
Char a1[] = {' A ', ' B ', ' C ', ' D ', ' E ', ' F ', ' G '};
Char a2[] = {' H ', ' I ', ' J ', ' K ', ' L ', ' M ', ' N '};
If:
sprintf (S, "%s%s", a1, A2); Don ' t do that!
There's a nine-to-ten problem. Can be changed to:
sprintf (S, "%7s%7s", a1, A2);
is not good to go, the right should be:
sprintf (S, "%.7s%.7s", a1, A2);//produce: "ABCDEFGHIJKLMN"
This can be compared to the "%m.nf" of the printed floating-point number, and in "%m.ns", m indicates the width (the length of the string is insufficient to fill the space, and then the actual width is printed), and N represents the most characters taken from the corresponding string. Usually when the string is printed, M is not much use, or the number of n after the dot is used more. Naturally, you can also take only a subset of the characters before and after:
sprintf (S, "%.6s%.5s", a1, A2);//produce: "ABCDEFHIJKL"
In many cases, we may also want the numbers in these format controllers to specify the length information to be dynamic rather than statically specified, because many times the program does not know exactly how to take a few characters in a character array until it is run, and the dynamic width/precision setting functions The implementation of sprintf is also taken into account, and sprintf uses "*" to occupy a position where a constant number that would otherwise require a specified width or precision, and the actual width or precision can be supplied as other printed variables, so the example above can become:
sprintf (S, "%.*s%.*s", 7, A1, 7, A2);
Or:
sprintf (S, "%.*s%.*s", sizeof (A1), A1, sizeof (A2), a2);
In fact, the printed characters, integers, floating-point numbers, and so on are all dynamically assigned to those constant values, such as:
sprintf (S, "%-*d", 4, ' A '); Produce "65"
sprintf (S, "% #0 *x", 8, 128); Produces "0x000080″," # "produces 0X
sprintf (S, "%*.*f", 10, 2, 3.1415926); Produce "3.14″
4. Print address information
Sometimes when debugging a program, we might want to look at the address of some variable or member, because the address or pointer is just a 32-digit number, you can print them out using "%u" that prints unsigned integers:
sprintf (S, "%u", &i);
But usually people prefer to use 16 instead of 10 to display an address:
sprintf (S, "%08x", &i);
However, these are indirect methods, for address printing, SPRINTF provides a dedicated "%p":
sprintf (S, "%p", &i);
I think it's actually equivalent to:
sprintf (S, "%0*x", 2 * sizeof (void *), &i);
5. Use the return value of sprintf
Less attention is paid to the return value of the printf/sprintf function, but sometimes it is useful, SPRITNF returns the number of characters that this function call eventually prints into the character buffer. That is, every time the Sprinf call is over, you don't have to call again strlen to know the length of the result string. Such as:
int len = sprintf (S, "%d", I);
For a positive integer, Len equals the 10-digit number of the integer i.
The following is a complete example that generates random numbers between 10 [0, 100) and prints them into a character array s, separated by commas.
Copy Code code as follows:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main () {
Srand (Time (0));
Char s[64];
int offset = 0;
for (int i = 0; i < i++) {
Offset + = sprintf (s + offset, "%d,", rand ()% 100);
}
S[OFFSET-1] = '/n ';//The last comma is replaced by a newline character.
printf (s);
return 0;
}

Imagine that when you take a record out of a database and then want to connect their fields to a string in a certain way, you can use this method, and theoretically, he should be more efficient than strcat, because strcat each call needs to find the last one first. 0 ' position, and in the example given above, each time we use the sprintf return value to write down the position directly.
6. Frequently asked questions about using sprintf
sprintf is a variable parameter function, often problems, and as long as the problem is usually caused by the program crash memory access error, but the problem caused by the misuse of sprintf although serious, but it is easy to find, nothing but a few cases, Usually use the eye to see the wrong code more than a few more eyes.
?? Buffer overflow
The length of the first parameter is too short to say, give it a bigger spot. Of course, it may be the problem of the following parameters, we suggest that the parameter must be careful, and when printing a string, try to use the form "%.NS" to specify the maximum number of characters.
?? Forgot the first argument
The low-level can no longer be a low-level problem, used to use printf too accustomed. I often commit. :。 (
?? Variable parameter correspondence problem
Usually forget to provide a corresponding format of the variable parameter, resulting in all the wrong parameters, check and check it. Especially those parameters that correspond to the "*", are they provided? Do not put an integer corresponding to a "%s", the compiler will think you cheated her too far (compiler is obj and exe mother, should be a woman,:P).
7. strftime
sprintf also has a nice cousin: strftime, used specifically for formatting time strings, is a lot like her cousin, is also a large number of format control characters, but after all, small roomed forestall, she also wants the caller to specify the maximum length of the buffer, may be in order to shirk responsibility in the case of problems. Here's an example:
Copy Code code as follows:

time_t t = time (0);
A string that produces the format "Yyyy-mm-dd hh:mm:ss".
Char s[32];
Strftime (S, sizeof (s), "%y-%m-%d%h:%m:%s", LocalTime (&t));

Sprintf in MFC can also find his bosom friend: Cstring::format,strftime in MFC naturally also has her fellow: Ctime::format, this pair because from object-oriented where get sponsorship, write code more feel elegant.
8. PostScript
All of these features are described in this article, in the MSDN can be easily found, the author is based on their own experience, combined with some examples, some commonly used, useful, and may be a lot of beginners do not know the use of the introduction of a point, I hope we do not joke, also hope that everyone criticized.
Some people think that this kind of function with variable parameters can cause various problems, so it is not advocated to use. But I often still can't resist their powerful function of temptation, in the actual work has been used. In fact, C#.net supports the argument from the beginning, and Java5.0 also supports it in the very early days of the release.
① gets system time: void GetSystemTime (Lpsystemtime lpsystemtime); Here is an example:
Copy Code code as follows:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
void Main () {
SYSTEMTIME St; structure that defines the time to store
Char strtime[256];
int n=0;
GetSystemTime (&ST);
n = sprintf (strtime, "year:/t%d/n", st.wyear);
n + = sprintf (Strtime+n, "month:/t%d/n", st.wmonth);
n + = sprintf (Strtime+n, "day:/t%d/n", st.wday);
n + = sprintf (Strtime+n, "date:/t%d/n", St.wdayofweek);
n + = sprintf (Strtime+n, "hour:/t%d/n", St.whour);
n + = sprintf (Strtime+n, "minute:/t%d/n", St.wminute);
n + = sprintf (Strtime+n, "second:/t%d/n", St.wsecond);
n + = sprintf (Strtime+n, "millisecond:/t%d/n", st.wmilliseconds);
printf ("%s", strtime);
System ("pause");
}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.