"C Pitfalls and Defects" - Chapter 7 Portability Defects

7.1 Whether a character is a signed or unsigned integer

A common misconception is that if c is a character variable, use (unsigned)it to get the unsigned integer equivalent to c.

This will fail because when converting the character c to an unsigned integer, c will first be converted to an int, which may result in unexpected results.

7.2 Logical Operators

If we want to perform a logical right shift operation, set the type of the number we want to right shift to an unsigned type, and the left side will be filled with 0. If we want to perform an arithmetic right shift, we generally set the type to a signed type. (under VS2019 environment)

Note: During the shift operation, the number of shifts should not exceed the number of bytes occupied by the current data type. For example, the int type has 32 bytes, then the number of shift operations should be 0 to 31. This is an undefined operation on the device, and the number of shifts cannot be negative.

7.3 Memory location 0

NULLIt is illegal to use for any purpose other than assignment and comparison operations.

7.4 Case conversion

toupper is implemented as a function as follows:

int toupper(int c)
{
	if(c >= 'a' && c <= 'z')
		return c+'A' - 'a';
	return c;
}

tolower is similar to this

#define _toupper(c) ((c) + 'A' - 'a')
#define _tolower(c) ((c) + 'a' - 'A')

Even if toupper is used to judge the parameters, if it is not a lowercase letter, the original parameters will be returned, while _toupper will not judge the function.

appendix

  1. There are two lines of code below:

    printf(s);
    printf("%s",s);
    

    The two have different meanings. The first example will treat any %s character in the string s as an indicator of a format item, so the following characters will be treated as format codes. If any format code other than %% appears in the string s, and there is no corresponding parameter behind it, it will cause trouble. Whereas the second example will print any null-terminated string.

    Conclusion: If we want to print like this (printf(s)), then we have to change the % in the s string to %%, otherwise there will be a printing error.

  2. If a short integer appears as an argument to any function (including the printf function), it is automatically expanded to a normal-length integer, that is, an int.

  3. The width modifier never truncates an output field (i.e. numbers before the decimal point), when we use the width modifier to align a set of numbers by column, if a value is too large to fit in the column it is in, then it It will squeeze the position next to the value on the right side of the same row.

  4. For %e, %E, and %f format items, the precision modifier specifies the number of digits that should appear after the decimal point. Unless the flag (Flag) specifies otherwise, the decimal point will only actually appear in the printed value if the precision is greater than 0. Here is an example:image-20220306223404638

  5. For the %g and %G format specifiers, the precision modifier specifies the number of significant digits in the printed value. Unless the flags state otherwise, 0s that are not significant digits are discarded. If the decimal point is not followed by a number, the decimal point will also be removed.

    image-20220306224021458

  6. For % format items,The precision modifier (i.e. the number after the decimal point) specifies the number of characters that will be printed from the corresponding string. If the string contains fewer characters than specified by the precision modifier, the output will have fewer characters than specified by the precision modifier. If the number of characters contained in the string exceeds the number of characters specified by the precision modifier, the number of characters output will be the same as the number of characters specified by the precision modifier, that is, a situation similar to truncation occurs.

    image-20220306225432533

  7. The function of the sign self-reading + (placed after %) is to stipulate that each value to be printed should take its sign (positive or negative) as the first character when outputting. Therefore, ==non-negative numbers (including 0)== should be printed with a positive sign at the top. Negative numbers are preceded by a minus sign.

  8. When a blank character is used as a sign character, its meaning is: if a certain number is a non-negative number, insert a blank character in front of it. If the mark character + and the blank character appear in a format item at the same time, the final effect is based on the mark character +.

    E.g:

    image-20220307095839128

    When printing values ​​in scientific notation in fixed columns, the format items %e and %+e are much more useful than the normal format item %e. Because the positive sign (or blank) that appears in front of the non-negative number at this time ensures that the decimal points of all output values ​​will be aligned.

    E.g:

    image-20220307100958917

  9. The function of the sign character # is to fine-tune the format of the numerical output, and the specific format is related to the specific format item. The effect of adding the mark character # to the %o format item is to increase the precision of the numerical output when necessary (just let the first digit of the output be 0, which is already done).

    ==Note: %#o is not the same as 0%o, because 0%o prints the value 0 as 00, while %#o prints 0. ==Similarly, %#x and %#X require 0x or 0X to be added in front of the printed hexadecimal value respectively.

    The sign character # affects the floating-point format in two ways:

    • It requires that the decimal point must be printed, even if there are no digits after the decimal point
    • If used in %g or %G format items, the trailing 0 of the printed value will not be dropped.

    E.g:image-20220307102051616

  10. Variable field width and precision

    If we want to control the length of the printed string by means of macro definitions, for example, we will probably use it like the following:

    #define NAMESIZE 14
    printf(".......%.NAMESIZE ...",...,name,...);
    

    But it's useless to write like that,Because the scope of the preprocessor cannot reach the interior of the string. That is, macro definitions within strings cannot be replaced during preprocessing.

    solution:

    We need to replace the modifier with * either wide modifier or precision modifier. In this case, the printf function first takes the actual value of the field width or precision to be used from the argument list, and then uses that value to print the task. Therefore, the above example can be written like this:

    printf("%*.%*s\n",NAMESIZE,NAMESIZE,name);
    

    The code above is the same as the code below:

    printf("%*.%*s\n",14,14,name);
    

    See an example below:

    printf("%*%\n",n);
    

    The above formula will print a % minus sign in a segment-aligned manner in a field with a width of n characters, in other words, print n-1 blank characters first, followed by a % minus sign.

    Note: If * is used to replace the field width modifier, and the value of the opposite parameter is negative, then the effect is equivalent to treating the negative sign as a - identifier. . Therefore, if n is negative in the above example, the output is first a % minus sign, followed by -n-1 spaces

  11. There is a summary about the above:

    A few are distinguished below:

    (1)%m.nd:m means that the output occupies a total of m columns. If it is not enough, fill the space in front of the m column. If it is enough, the m column will not do any processing. n means that the number must have a total of n columns. .

    Note: m is a total of m characters including the negative sign (positive sign, 0x, 0), and n is a total of n numbers that only count numbers. The former is not enough to fill spaces, and the latter is not enough to fill 0.

    image-20220307112620666

    In most cases, we can use %. instead of %0, the effect is very close.

    Here is an example:

    image-20220307114910383

    (2)%m.ns:m means that the string outputs a total of m columns, and n means that the first n elements of the string are output to the right side of the entire m column. When n<m, use spaces to fill in the remainder on the left, when n >=m, no processing is performed.

    Here is an example:

    image-20220307115944317

    (3)%m.nf:m means that the number should be output in m columns in total, including the number of decimal points and decimals, n represents the number of decimals, when the number of decimal places of the floating-point number is greater than n, it is rounded (1-5 rounding). Drop, 6-9 carry), when it is less than n, add 0 to the back

    Here is an example:

    image-20220307120249656

Guess you like

Origin blog.csdn.net/m0_57304511/article/details/123895672