1.. title:: clang-tidy - bugprone-signed-char-misuse 2 3bugprone-signed-char-misuse 4=========================== 5 6`cert-str34-c` redirects here as an alias for this check. For the CERT alias, 7the `DiagnoseSignedUnsignedCharComparisons` option is set to `false`. 8 9Finds those ``signed char`` -> integer conversions which might indicate a 10programming error. The basic problem with the ``signed char``, that it might 11store the non-ASCII characters as negative values. This behavior can cause a 12misunderstanding of the written code both when an explicit and when an 13implicit conversion happens. 14 15When the code contains an explicit ``signed char`` -> integer conversion, the 16human programmer probably expects that the converted value matches with the 17character code (a value from [0..255]), however, the actual value is in 18[-128..127] interval. To avoid this kind of misinterpretation, the desired way 19of converting from a ``signed char`` to an integer value is converting to 20``unsigned char`` first, which stores all the characters in the positive [0..255] 21interval which matches the known character codes. 22 23In case of implicit conversion, the programmer might not actually be aware 24that a conversion happened and char value is used as an integer. There are 25some use cases when this unawareness might lead to a functionally imperfect code. 26For example, checking the equality of a ``signed char`` and an ``unsigned char`` 27variable is something we should avoid in C++ code. During this comparison, 28the two variables are converted to integers which have different value ranges. 29For ``signed char``, the non-ASCII characters are stored as a value in [-128..-1] 30interval, while the same characters are stored in the [128..255] interval for 31an ``unsigned char``. 32 33It depends on the actual platform whether plain ``char`` is handled as ``signed char`` 34by default and so it is caught by this check or not. To change the default behavior 35you can use ``-funsigned-char`` and ``-fsigned-char`` compilation options. 36 37Currently, this check warns in the following cases: 38- ``signed char`` is assigned to an integer variable 39- ``signed char`` and ``unsigned char`` are compared with equality/inequality operator 40- ``signed char`` is converted to an integer in the array subscript 41 42See also: 43`STR34-C. Cast characters to unsigned char before converting to larger integer sizes 44<https://wiki.sei.cmu.edu/confluence/display/c/STR34-C.+Cast+characters+to+unsigned+char+before+converting+to+larger+integer+sizes>`_ 45 46A good example from the CERT description when a ``char`` variable is used to 47read from a file that might contain non-ASCII characters. The problem comes 48up when the code uses the ``-1`` integer value as EOF, while the 255 character 49code is also stored as ``-1`` in two's complement form of char type. 50See a simple example of this bellow. This code stops not only when it reaches 51the end of the file, but also when it gets a character with the 255 code. 52 53.. code-block:: c++ 54 55 #define EOF (-1) 56 57 int read(void) { 58 char CChar; 59 int IChar = EOF; 60 61 if (readChar(CChar)) { 62 IChar = CChar; 63 } 64 return IChar; 65 } 66 67A proper way to fix the code above is converting the ``char`` variable to 68an ``unsigned char`` value first. 69 70.. code-block:: c++ 71 72 #define EOF (-1) 73 74 int read(void) { 75 char CChar; 76 int IChar = EOF; 77 78 if (readChar(CChar)) { 79 IChar = static_cast<unsigned char>(CChar); 80 } 81 return IChar; 82 } 83 84Another use case is checking the equality of two ``char`` variables with 85different signedness. Inside the non-ASCII value range this comparison between 86a ``signed char`` and an ``unsigned char`` always returns ``false``. 87 88.. code-block:: c++ 89 90 bool compare(signed char SChar, unsigned char USChar) { 91 if (SChar == USChar) 92 return true; 93 return false; 94 } 95 96The easiest way to fix this kind of comparison is casting one of the arguments, 97so both arguments will have the same type. 98 99.. code-block:: c++ 100 101 bool compare(signed char SChar, unsigned char USChar) { 102 if (static_cast<unsigned char>(SChar) == USChar) 103 return true; 104 return false; 105 } 106 107.. option:: CharTypdefsToIgnore 108 109 A semicolon-separated list of typedef names. In this list, we can list 110 typedefs for ``char`` or ``signed char``, which will be ignored by the 111 check. This is useful when a typedef introduces an integer alias like 112 ``sal_Int8`` or ``int8_t``. In this case, human misinterpretation is not 113 an issue. 114 115.. option:: DiagnoseSignedUnsignedCharComparisons 116 117 When `true`, the check will warn on ``signed char``/``unsigned char`` comparisons, 118 otherwise these comparisons are ignored. By default, this option is set to `true`. 119