Printf may be a second function that many programmers have come into contact with the C language (I guess the first is main), say, naturally the old friend, but do you know more about this old friend? Do you know how much your twins brothers sprintf? When constructing various types of data into a string, the powerful feature of Sprintf rarely disappoints you.
Since Sprintf is almost the same as the Printf, only the destination of print is different, the former prints into the string, the latter, then output on the command line. This also causes sprintf to be much useful than Printf. So this paper focuses on Sprintf, sometimes inserting with PRITNF.
Sprintf is a variable-gate function, defined as follows:
INT Sprintf (Char * Buffer, Const Char * Format [, Argument] ...);
In addition to the first two parameter types, you can pick up any multiple parameters. And its essence, obviously in the second parameter: format strings.
Both PRINTF and SPRINTF use formatted strings to specify the format of the string, and use some format spectrial specifence (Format Specifications) at the beginning of the format string to provide corresponding variables in the backward parameters of the rear. The final function will replace the specifier in the variable of the corresponding position, generate a buffer you want.
Formatted numeric string
One of the most common applications of sprintf is too printed into the string, so Spritnf can replace ITOA in most cases. Such as:
// Print the integer 123 into a string saved in s.
Sprintf (s, "% d", 123); // Generate "123"
You can specify the width, insufficient left resilience:
Sprintf (S, "% 8D% 8D", 123, 4567); // Produce: "123 4567"
Of course, you can align the left:
Sprintf (s, "% -8d% 8D", 123, 4567); // generation: "123 4567"
You can also print according to 16-based printing:
Sprintf (s, "% 8x", 4567); // lowercase 16-based, the width accounts for 8 positions, right alignment
Sprintf (s, "% -8x", 4568); // uppercase 16-based, the width is 8 positions, left alignment
In this way, an integer's 16-enrich string is easy, but when we print 16 credit content, we usually want to have an equivalent format of the left to supplement 0. What should I do? Very simple, add 0 in front of the number indicating the width.
Sprintf (s, "% 08x", 4567); // generation: "000011d7"
10% of "% D" is also used as well as this left to supplement 0.
Here, you should pay attention to a symbol extension problem: For example, if we want to print a short integer (short) -1 memory 16 credit representation, on the Win32 platform, a short type occupies 2 bytes, so we naturally hope to use 4 A 16-entered number to print it:
Short Si = -1;
Sprintf (s, "% 04x", si);
Generate "ffffffffff", what is going on? Because spritnf is a variable-gate function, in addition to the two parameters, the back parameters are not type security, and the function can not know how only one "% X" can know when the first function call before the parameter stack is pressed. In the end, it is a 4-byte integer or a short integer of 2 bytes. Therefore, the unified 4-byte processing method is taken, causing the parameter stack to make a symbol extension, expanded to 32-bit integers -1, printing 4 positions are not enough, print 32-bit integers -1 8-bit bits. If you want to see the original face of Si, you should let the compiler do 0 expansions rather than symbol extensions (扩 二 二 左 0 0): Sprintf (S, "% 04x", (unsigned short) Si );
Yes. or:
UNSIGNED SHORT SI = -1;
Sprintf (s, "% 04x", si);
Sprintf and Printf can also press 8-based printing a nutrient, using "% O". Note that 8 binders and 16 are not printing negative numbers, which are not symbol, which is actually the direct 16-coded or 8 binary representation of the internal encoding of the variable.
2. Control floating point number print format
Print and format control of floating point numbers is another common function of sprintf, floating point number uses format "% F" control, the default retains 6 digits after the decimal point, such as:
Sprintf (s, "% f", 3.1415926); // Generate "3.141593"
But sometimes we want yourself to control the width of the print and the decimal number. At this time, you should use: "% m.nf" format, where m represents the width of the print, n represents the number of digits after the decimal point. such as:
Sprintf (s, "% 10.3f", 3.1415626); // produces: "3.142"
Sprintf (s, "% -10.3f", 3.1415626); // generation: "3.142"
Sprintf (s, "% .3f", 3.1415626); // does not specify the total width, produce: "3.142"
Pay attention to a problem, you guess
INT i = 100;
Sprintf (s, "% .2f", i);
What will play Dongdong? "100.00"? right? I will try it yourself, and try it below:
Sprintf (s, "% .2f", (double) i);
The first one is definitely not the correct result, the cause is the same as mentioned above, the caller when the parameter stack does not know that the format control computation corresponding to the i is "% f". When the function execution function itself doesn't know that the integer is being pressed into the stack, the four bytes of poor storage integer i are unsolicited as a floating point number format, the whole chaos.
However, if someone is interested in using a floating point number, you can use this method to verify that your hand-arranged results are correct. J
3. Character / ASCII code control
We know that in the C / C language, Char is also a normal scalable type. In addition to the length, it is not essentially different from short, int, long, but it is used to express the character and string of characters. . (Perhaps this type is called "byte", and then it can now use Byte or short to define the CHAR through TypeDef according to the actual situation, so more appropriately), using "% D" or "% x" printing A character can derive its 10 credit or 16-based ASCII code; in turn, use "% C" to print an integer, you can see the ASCII characters it corresponds to. The following block prints all the ASCII code controls of all visible characters to the screen (here the printf, pay attention to "#" automatically add "0x" prefixed to "0x" with "% x".
For (int i = 32; i <127; i ) {
Printf ("[% C]:% 3D 0x% # 04x / n", i, i, i);
}
4. Connect the string
Sprintf's format control string can be inserted into a variety of things, and finally "connect them into a string", naturally connect the string, so that in many occasions can replace STRCAT, but the sprintf can connect multiple strings once again (natural It is also possible to insert other content in both middle, in short, very flexible. such as:
Char * who = "i";
Char * whom = "9cbs";
Sprintf (s, "% s love% s.", WHO, WHOM); // generation: "i love 9cbs."
STRCAT can only connect to the string (a character array of '/ 0' ending or called character buffer, null-terminated-string, but sometimes we have two character buffers, they are not ending with '/ 0'. For example, many characters from the third-party library function, read from hardware or network transfers, they do not have a corresponding '/ 0' after each sequence of characters. If you connect directly, no matter whether sprintf or Strcat will definitely lead to illegal memory operation, and Strncat requires at least the first parameter is a null-terminated-string, what should I do? We naturally think of the previous introduction to print integers and floating point numbers, you can specify the width, the string is the same. such as:
CHAR A1 [] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
CHAR A2 [] = {'h', 'I', 'J', 'K', 'L', 'M', 'N'};
in case:
Sprintf (S, "% S% S", A1, A2); // Don't do this!
Ten eight nine must have problems. Can it be modified:
Sprintf (S, "% 7S% 7S", A1, A2);
Nothing, where is it, the right thing should be:
Sprintf (S, "% .77% .7s", A1, A2); // Generate: "Abcdefghijklmn"
This can be classified than the "% m.nf" of the printed floating point. In "% m.ns", M represents the occupation width (the semaphore is not enough when the string is less than the length of the string, and the actual width is printed). The number of characters that are taken in the string. Usually m is not very large when the string is printed, or there is more than the nodes. Natural, you can only take some characters before, Sprintf (S, "%. 6S% .5s", A1, A2); // Generate: "Abcdefhijkl"
In many cases, we may also hope that the numbers used to specify length information in these format controls are dynamic instead of static designation, because many times, the program will be clear when the program needs to take a few in the number of characters. A character, this dynamic width / precision setting function is also considered in the implementation of the sprintf, and the sprintf uses "*" to occupy a position of a constant number of a specified width or accuracy, or the actual width or Precision can be provided as the other printed variables, so, the above example can becomes:
Sprintf (s, "%. * s%. * s", 7, A1, 7, A2);
or:
Sprintf (s, "%. * s%. * s", sizeof (A1), A1, SIZEOF (A2), A2);
In fact, the print characters, integers, floating point numbers, etc., which are described earlier, can dynamically specify those constant values, such as:
Sprintf (s, "% - * d", 4, 'a'); // Generate "65"
Sprintf (s, "% # 0 * x", 8, 128); // Generate "0x000080", "#" generated 0x
Sprintf (s, "% *. * f", 10, 2, 3.1415926); // Generate "3.14"
5. Print address information
Sometimes when you debug a procedure, we may want to view the address of certain variables or members, because the address or pointer is just a 32-bit number, you can print them out with "% u" that prints unsigned integers:
Sprintf (s, "% u", & i);
But usually people still like to use 16 credits rather than 10 credits to display an address:
Sprintf (s, "% 08x", & i);
However, these are indirect methods, for address printing, Sprintf provides special "% P":
Sprintf (s, "% p", & i);
I think it is actually equivalent to:
Sprintf (s, "% 0 * x", 2 * sizeof (void *), & i);
6. Use sprintf return value
Someone pays attention to the return value of the PrintF / Sprintf function, but sometimes it is useful, and the spritnf returns the number of characters in this function call to the character buffer. That is to say, every time the Sprinf call is over, you have no need to call a Strlen that has already known the length of the result string. Such as:
INT LEN = Sprintf (S, "% D", i);
For positive integers, LEN is equal to the 10-encyclopedia number of integer i.
The following is a complete example, generates a random number between [0, 100), and print them into a character array S, separated by a comma.
#include
#include
#include
Int main () {
SRAND (Time (0));
Char s [64];
INT OFFSET = 0;
For (int i = 0; i <10; i ) {
OFFSET = Sprintf (S Offset, "% D,", RAND ()% 100);
}
s [offset - 1] = '/ n'; // convert the last comma to a newline character.
PRINTF (S);
Return 0;
}
Imagine a record when you take a record from the database, and then you want to connect their various fields to a string, you can use this method, in theory, he should be higher than the constant STRCAT efficiency, because Strcat needs to find the last '/ 0' position each time, and in the example given above, we use the sprintf return value to record this location each time.
7. FAQ using sprintf
Sprintf is a changeable function, often problematic, and as long as the problem is usually the memory access error that can cause the crash, it is very serious, it is easy to find, nothing more than a few The situation, usually use the eyes to look at the wrong code more look.
Ø Buffer overflow
The length of the first parameter is too short, not to say, give a big place. Of course, it may also be the problem of the back parameters. It is recommended to change the parameters to be careful, and when the string is printed, try to specify the maximum number of characters in the form of "% .ns".
Ø Forgot the first parameter
Low levels can no longer be low-level issues, using Printf to use it too used to. // I will do it. :. (
Ø Severe ginseng corresponding problem
It is usually forgotten to provide a variety of parameters corresponding to a format, causing the future parameters to dislocation, check check. Especially those parameters corresponding to "*" are provided? Don't take an integer to a "% s", the compiler will feel that you are bullying too much (the compiler is Obj and Exe mother, should be a woman,: p).
8. StrFTIME
Sprintf has a good cousin: strftime, specifically used to format the time string, usage is very similar to her, is also a lot of format control, but after all, the little girl is in mind, she also wants to be called to specify buffers The maximum length of the area may be to shirk responsibility when there is a problem. Here is an example:
Time_t t = time (0);
/ / Generate a string of "YYYY-MM-DD HH: MM: SS" format.
Char s [32];
Strftime (S, SIZEOF (S), "% Y-% M-% D% H:% M:% S", LOCALTIME (& T));
Sprintf can also find his voice in the MFC: cString :: Format, StrFTIME naturally also has her equivalents in the MFC: CTIME :: Format, this pair of sponsored from the object-oriented object, the code used to write Elegant.
9. Postscript
All of this article introduced in MSDN can be easily found in the MSDN, the author only uses some examples according to their own experience, uses some common, useful, and may introduce the usage of many beginners. One point, I hope everyone should not jokes, and I hope everyone criticizes.
Some people think that this function of this band-ginseng will cause various problems, so it is not advocated. But the author does not resist the temptation of their powerful features, in practice. In fact, C # .NET supports changing ginseng from the beginning, Java 5.0 just released also supports parameters. Thanks Ericzhangali (another space) carefully reviewed the full manuscript, corrected a lot of small mistakes, and put forward some suggestions. I also thank Laomai (old) to read the full manuscript and gave suggestions for adding some content.