Deep understanding of C language sprintf Functions

Source: Internet
Author: User
Tags 04x

Printf may be the second function that many programmers encounter when learning C language (I guess the first function is main). It is naturally an old friend. However, do you know much about this old friend? Do you know more about sprintf? When constructing data of various types into strings, the powerful features of sprintf seldom disappoint you.
Since sprintf and printf have almost the same usage, but the printing destination is different, the former is printed into the string, and the latter is directly output on the command line. This also makes sprintf much more useful than printf. So this article focuses on sprintf, which is sometimes interspersed with pritnf.
Sprintf is a variable parameter function, which is defined as follows:
Int sprintf (char * buffer, const char * format [, argument]… );
In addition to the fixed types of the first two parameters, you can take over multiple parameters later. Its essence is obviously on the second parameter: Format String.
Both printf and sprintf use formatted strings to specify the string format. Some format specifiers (format specifications) starting with "%" are used inside the format string to occupy a position, the variable is provided in the variable parameter list, and the function will replace the specifier with the variable at the corresponding position to generate the string that the caller wants.
1. format the numeric string
One of the most common applications of sprintf is to print Integers to strings. Therefore, spritnf can replace itoa in most cases. For example:
// Print the integer 123 into a string and save it in s.
Sprintf (s, "% d", 123); // generate "123 ″
You can specify the width. If the width is insufficient, spaces are filled on the left:
Sprintf (s, "% 8d % 8d", 123,456 7); // generate: "123 4567 ″
Of course, you can also align left:
Sprintf (s, "%-8d % 8d", 123,456 7); // generate: "123 4567 ″
You can also print the data in hexadecimal format:
Sprintf (s, "% 8x", 4567); // lowercase hexadecimal format, where the width occupies 8 positions and is right aligned
Sprintf (s, "%-8X", 4568); // in hexadecimal notation, the width occupies 8 positions and is left aligned.
In this way, the hexadecimal string of an integer is easy to obtain, but when printing the hexadecimal content, we usually want an equal-width format with 0 on the left, what should we do? Simply add 0 to the number that represents the width.
Sprintf (s, "% 08X", 4567); // generate: "201711d7 ″
You can also use this left-side 0 Complement Method to print the 10-in-hexadecimal format with "% d" above.
Pay attention to a symbol extension problem: for example, if we want to print a short INTEGER (short)-1 memory hexadecimal representation, on the Win32 platform, A short type occupies 2 bytes, So we naturally want to print it with 4 hexadecimal numbers:
Short si =-1;
Sprintf (s, "% 04X", si );
Why is "FFFFFFFF" generated? Because spritnf is a Variable Parameter Function, except the first two parameters, the following parameters are not of type security, there is no way for a function to know whether a 4-byte integer or a 2-byte short integer is pressed in the parameter stack before the function call through a "% X "., therefore, a 4-byte processing method is adopted, which leads to the symbol extension during parameter pressure stack, which is a 32-bit integer-1. When printing, the four locations are insufficient, print out the 8-bit 16 hexadecimal values of 32-bit integer-1. If you want to see the original form of si, you should let the compiler perform 0 extension instead of symbol extension (the left side of the binary complement 0 rather than the sign bit during extension ):
Sprintf (s, "% 04X", (unsigned short) si );
You can. Or:
Unsigned short si =-1;
Sprintf (s, "% 04X", si );
Sprintf and printf can also print integer strings in octal, using "% o ". Note that both the octal and hexadecimal formats do not print negative numbers. They are all unsigned. In fact, they are the direct hexadecimal or octal representation of the variable's internal code.
2. Control the floating point printing format
The printing and format control of floating point numbers is another common function of sprintf. Floating Point Numbers are controlled by the format character "% f". By default, the six digits after the decimal point are retained, for example:
Sprintf (s, "% f", 3.1415926); // generate "3.141593 ″
But sometimes we want to control the print width and decimal places by ourselves, then we should use the format "% m. nf", where m indicates the print width, n indicates the number of digits after the decimal point. For example:
Sprintf (s, "% 10.3f", 3.1415626); // generate: "3.142 ″
Sprintf (s, "%-10.3f", 3.1415626); // generate: "3.142"
Sprintf (s, "%. 3f", 3.1415626); // The total width is not specified and "3.142" is generated ″
Pay attention to one question, you guess
Int I = 100;
Sprintf (s, "%. 2f", I );
What will it do? 100.00 "? Right? Try it on your own and try the following:
Sprintf (s, "%. 2f", (double) I );
The first one is definitely not the correct result, because, as mentioned above, the caller does not know that the format controller corresponding to I is "% f" when the parameter is pressed ". When a function is executed, the function itself does not know that the number pushed to the stack in the current year is an integer, so the four bytes that saved the integer I were forcibly interpreted as a floating-point number.
However, if someone is interested in manually encoding a floating point number, you can use this method to check whether the result of your manual arrangement is correct. J
Character/Ascii code comparison
We know that in C/C ++, char is also a common scalable type. In addition to the word length, it has no essential difference with short, int, and long, it is used to represent characters and strings. (This type may be called "byte" in the past, and now we can use byte or short to define char through typedef according to the actual situation, which is more appropriate)
Therefore, print a character using "% d" or "% x" to obtain its 10-or 16-digit ASCII code. In turn, print an integer using "% c" to see its ASCII characters. The following section prints the ASCII code table of all visible characters to the screen (printf is used here, note that "#" and "% X" are automatically prefixed with "0X" in hexadecimal notation ):
For (int I = 32; I <127; I ++ ){
Printf ("[% c]: % 3d 0x % # 04X/n", I, I );
}
3. connection string
Since the sprintf format control string can insert various things and "connect them together", it can naturally connect strings, which can replace strcat in many occasions, but sprintf can connect multiple strings at a time (it can also insert other content in them at the same time, in short, it is very flexible ). For example:
Char * who = "I ";
Char * whom = "CSDN ";
Sprintf (s, "% s love % s.", who, whom); // generate: "I love CSDN ."
Strcat can only connect strings (an array of characters ending with '/0' or a character buffer, null-terminated-string), but sometimes we have two character buffer segments, they do not end with '/0. For example, a large number of character streams read from hardware or network transmission, they may not end with a corresponding '/0' after each character sequence. If you connect directly, whether sprintf or strcat will certainly lead to illegal memory operations, and strncat also requires at least the first parameter to be null-terminated-string. What should we do? We naturally remember that the width can be specified when we first introduced printing integers and floating-point numbers, and the strings are the same. For example:
Char a1 [] = {'A', 'B', 'C', 'D', 'E', 'F', 'G '};
Char a2 [] = {'h', 'I', 'J', 'k', 'l', 'M', 'n '};
If:
Sprintf (s, "% s", a1, a2); // Don't do that!
In, something went wrong. Can it be changed:
Sprintf (s, "% 7 s % 7s", a1, a2 );
It's not good where to go. The correct one should be:
Sprintf (s, "%. 7 s %. 7s", a1, a2); // generate: "ABCDEFGHIJKLMN"
This can be analogous to printing the "% m. nf ", in" % m. in "ns", "m" indicates the width occupied (when the string length is insufficient, fill in spaces. If the length exceeds the limit, print it according to the actual width). "n" indicates the maximum number of characters used from the corresponding string. Generally, m is useless when printing strings, but n is usually used after the dot. Naturally, you can only take part of the characters before and after:
Sprintf (s, "%. 6 s %. 5s", a1, a2); // generate: "ABCDEFHIJKL"
In many cases, we may also want the numbers in these format controllers to specify length information to be dynamic, rather than static, because many times, when the program is running, it will know exactly how many characters in the character array need to be taken. This dynamic width/precision setting function is also taken into account in the implementation of sprintf, sprintf uses "*" to occupy a position that originally requires a constant number with a specified width or accuracy. Similarly, the actual width or accuracy can be provided like other printed variables, so the preceding example can be changed:
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, and floating-point numbers described above can all dynamically specify the constant values, such:
Sprintf (s, "%-* d", 4, 'A'); // generate "65"
Sprintf (s, "% #0 * X", 8,128); // generate "0X000080" and "#" to generate 0X
Sprintf (s, "% *. * f", 10, 2, 3.1415926); // generate "3.14 ″
4. Print the address information
Sometimes, when debugging a program, we may want to view the addresses of some variables or members. Because the addresses or pointers are only 32-bit numbers, you can print the unsigned integers "% u:
Sprintf (s, "% u", & I );
However, people usually prefer to use hexadecimal instead of hexadecimal to display an address:
Sprintf (s, "% 08X", & I );
However, these are indirect methods. For address printing, sprintf provides a special "% p ":
Sprintf (s, "% p", & I );
I think it is actually equivalent:
Sprintf (s, "% 0 * x", 2 * sizeof (void *), & I );
5. Use the sprintf Return Value
Few people pay attention to the return values of the printf/sprintf function, but sometimes it is useful. spritnf returns the number of characters that the function call finally prints to the character buffer. That is to say, after each sprinf call ends, you do not need to call strlen again to know the length of the result string. For example:
Int len = sprintf (s, "% d", I );
For a positive integer, len is equal to the 10-digit digits of the integer I.
The following is a complete example, which generates a random number between 10 [0,100) and prints them into an array of characters (s) separated by commas. Copy codeThe Code is 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 <10; I ++ ){
Offset + = sprintf (s + offset, "% d,", rand () % 100 );
}
S [offset-1] = '/N'; // Replace the last comma with a line break.
Printf (s );
Return 0;
}

Imagine that when you extract a record from the database and want to connect each of their fields into a string according to certain rules, you can use this method. Theoretically, it should be more efficient than the continuous strcat, because each call to strcat needs to first find the last '/0' position, and in the example given above, every time we use the sprintf return value to write down this position directly.
6. FAQs about using sprintf
Sprintf is a variable parameter function, which often causes problems when used, and as long as there is a problem, it is usually a memory access error that can cause the program to crash, but fortunately the problems caused by sprintf misuse are serious, but it is easy to find out, nothing more than a few situations, usually with the eyes of the error code to see a few more eyes.
?? Buffer Overflow
The length of the first parameter is too short. If you don't want to say it, just give it a bigger one. Of course, it may also be a problem with the following parameters. We recommend that you be careful with the corresponding parameters. When printing a string, try to use the "%. ns" format to specify the maximum number of characters.
?? The first parameter is missing.
Low-level users cannot have low-level problems. They are too familiar with printf. // It is common. :. (
?? An error occurred while changing the parameter.
Generally, you forget to provide variable parameters corresponding to a certain format character, which leads to misplacement of all subsequent parameters. Check the parameters. Are all parameters corresponding to "*" provided? Do not map an integer to a "% s". The compiler will think that you are deceiving her too much (the compiler is the mother of obj and exe, which should be a female: P ).
7. strftime
Sprintf also has a good cousin: strftime, which is specially used to format the time string. Its usage is very similar to that of her cousin. It is also a lot of format control characters, but after all, the girl's family is fine, she also needs the caller to specify the maximum length of the buffer, probably to shirk responsibility in case of problems. Here is an example:Copy codeThe Code is as follows: time_t t = time (0 );
// Generate a string in "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 its Zhiyin in MFC: CString: Format. strftime also has her same path in MFC: CTime: Format, the code used to write is more elegant because of the sponsorship of the object-oriented program.
8. Postscript
All of the functions described in this article can be easily found in MSDN. based on my own experience and some examples, I will use some common and useful functions, I may have introduced some usage that many beginners don't know. I hope you don't want to joke or criticize and correct it.
Some people think that this function with variable parameters will cause various problems and therefore it is not recommended to use it. However, I have never been able to resist the temptation of their powerful functions and have been using them in practical work. In fact, C #. NET supports variable parameters from the beginning, and Java5.0, which was just released, also supports variable parameters.
① Obtain the System time: void GetSystemTime (LPSYSTEMTIME lpSystemTime); The following is an example:Copy codeThe Code is as follows: # include <windows. h>
# Include <stdio. h>
# Include <stdlib. h>
Void main (){
SYSTEMTIME st; // defines the struct of the storage time
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.