This commit is contained in:
Miloslav Ciz 2024-04-02 22:47:48 +02:00
parent 491c5ff885
commit b9fd8d7532
17 changed files with 1909 additions and 1777 deletions

View file

@ -18,6 +18,18 @@ There are tools for detecting undefined behavior, see e.g. [clang](clang.md)'s U
**No specific [endianness](endian.md) or even encoding of numbers is specified**. Nowadays little endian and [two's complement](twos_complement.md) is what you'll encounter on most platforms, but e.g. [PowerPC](ppc.md) uses big endian ordering.
**Unlike with global variables, values of uninitialized local variables are not defined**. Global variables are automatically initialized to 0 but not local ones -- this can lead to nasty bugs as sometimes local variables WILL be initialized with 0 but stop being so e.g. under different optimization level, so watch out. Demonstration:
```
int a; // auto initialized to zero
int main(void)
{
int b; // undefined value!
return 0;
}
```
**Order of evaluation of operands and function arguments is not specified**. I.e. in an expression or function call it is not defined which operands or arguments will be evaluated first, the order may be completely random and the order may differ even when evaluating the same expression at another time. This is demonstrated by the following code:
```
@ -114,10 +126,26 @@ Of course this applies to other languages as well, but C is especially known for
## Other
Watch out for **operator precedence**! Bracket expressions if unsure, or just to increase readability for others.
Basic things: `=` is not `==`, `|` is not `||`, `&` is not `&&`, array indices start at 0 (not 1) and so on. There are also some deeper gotchas like `a/*b` is not `a / *b` (the first is comment).
Also watch out for this one: `!=` is not `=!` :) I.e. `if (x != 4)` and `if (x =! 4)` are two different things, the first means *not equal* and is usually what you want, the latter is two operations, `=` and `!`, the tricky thing is it also compiles and may work as expected in some cases but fail in others, leading to a very nasty bug. Same thing with `-=` vs `=-` and so on. See also [downto](downto.md) operator.
Another common, mostly beginner mistake is a semicolon after if or while condition -- this compiles but doesn't work correctly. Notice the difference between these two if statements:
```
if (a == b);
puts("aaa"); // will print always
if (a == b)
puts("aaa"); // will print only if a == b
```
Beginners similarly often forget breaks in switch statement, which works but usually not as you want -- thankfully compilers warn you about this.
Watch out for **operator precedence**! C infamously has weird precedence with some special operators, bracket expressions if unsure, or just to increase readability for others. Also nested ifs with elses can get tricky -- again, use curly brackets for clarity in your spaghetti code.
**[Preprocessor](preprocessor.md) can give you headaches** if you use it in overcomplicated ways -- ifdefs and macros are fine, but too many nesting can create real mess that's super hard to debug. It can also quite greatly slow down compilation. Try to keep the preprocessing code simple and flat.
Also watch out for this one: `!=` is not `=!` :) I.e. `if (x != 4)` and `if (x =! 4)` are two different things, the first means *not equal* and is usually what you want, the latter is two operations, `=` and `!`, the tricky thing is it also compiles and may work as expected in some cases but fail in others, leading to a very nasty bug.
Watch out for **[macro](macro.md) arguments**, always bracket them because they get substituted on text level. Consider e.g. a macro `#define divide(a,b) a / b`, and then doing `divide(3 + 1,2)` -- this gets expanded to `3 + 1 / 2` while you probably wanted `(3 + 1) / 2`, i.e. the macro should have been defined as `#define divide(a,b) (a) / (b)`.
This is not really a pitfall, rather a headscratcher, but don't forget to link math library with `-lm` flag when using using the `math.h` library.