None of those are "violations" of "common C" practices. This is like when someone says "never begin a sentence with but."
Global scope variables are
sometimes considered problematic in
C++ land for a variety of reasons, most importantly you can't control the scope of the variable. There are initialization pattern errors that occur when using globals in C++, such as you can't be sure in what order objects are constructed in memory. This is why things like the singleton anti-pattern exist, they are classes which can be constructed to ensure a global, singular variable
in c++. In C, there are no classes, and thus variables don't have constructors. It's not at all a bad thing to create a global variable in C, you'll have to initialize them by hand anyhow in an init function so construction order is not usually a problem. There are many, many instances where using a "global" variable is preferable and saves memory, in fact. You can save on the act of needing to push or pop variables onto the stack to pass the variable to a function call, since the variable doesn't need to be included as a function parameter. Even if you were just passing a pointer to a function instead of an entire copy of the object in question, you still have to pop and push that pointer onto the stack frame which is inefficient. Declaring a variable as global allows the compiler to reference the address as a constant during preprocessing, so my function can manipulate the global variable and the preprocessor will simply substitute in the constant address of the variable in place of calls to the variable.
This is related to the way executables are actually organized within a binary. There are multiple segments of a program, which is where constant and global variables are stored. Declaring variables as global allows them to reside in either the .data section of the executable or the .text section of the executable, as opposed to a stack frame. The compiler can look at usage of the global variable and determine if it needs to be read-only or read-write and assign it to the .data or .text segment appropriately for a performance increase.
If you're asking why someone would care that much about the cost of pushing or popping a variable onto the stack frame,
this is the gameboy advance. Those kinds of optimizations matter. For example Doom uses global variables all over the place. It's actually pretty hard to write very performant C code without using global variables, as multiple performance patterns rely on them.
The same can go for "reusing code" Firstly, a compiler can determine if reused code would benefit from refactoring into an external call and break it out that way. But they usually do not, because "never repeat code" is actually an aphorism that
decreases performance. Jumping around in code is costly, it violates instruction cache. When code is read and executed, the way the GBA does this is by fetching 256 bytes of assembly code at a time and dumps it into Instruction cache. Game code is executed from IWRAM (instruction cache), not the cart directly. If your program executes linearly, this is good, because when it fetches instructions for the cache, those 256 bytes not only cover the next immediate instruction, but several instructions to be performed after. This is because moving things into cache is slower than reading things out of cache. The goal is to limit the number of times something must be moved into cache, and read cache as many times as possible.
Accessing a function destroys this, because the code is not being read linearly. A jump command takes an address to move the program counter to, which incurs a cache miss. This is because, unless you're purposefully writing extremely tight and tiny code, your function address will assuredly be more than 256 bytes away from the last opcode. So by telling the console to jump to a function, you are forcing it to load another 256 bytes into instruction cache to read, and then when the function ends, it must return to the original address and resume executing, which means
another cache hit.
Keeping code local is how you write optimized code. This is the entire reason inlining exists -- it allows one to embed an entire function inside of another function, at the expense of binary size for the advantage of fetch execution. Also, not to harp on the stack, but depending on
where your function resides, the jump command will grow bigger. If, for example, your jumping-to function is located very, very far away from your original calling function, the value of the address to jump to needs to be bigger, which means more bits to represent the size of the address, which means it takes longer to pop onto the stack. There are actually multiple jump commands, differing on the distance being jumped, to allow programmers to optimize their jumps, precisely because jumping is inefficient. This is known as
locality of reference, and games do it all the time in order to make things run faster. Mario 64 uses data duplication
all over the place for example.
Finally... headers are where you store definitions. That's the normal convention. You store your definitions in your headers because they're if-guarded. This makes them portable. The preprocessor only ever copies the definition once into the translation unit at preprocessing. If you define definitions outside of headers multiple translation units can't really share their definitions without multiple redefines (which throws a warning). I've never, ever heard anyone tell people not to define things in their header. Headers are
where you define things.
This post sounds like something someone wrote to try and stir up some controversy. They're spouting aphorisms that are told to absolute beginners to keep them from messing themselves up as they're learning, and pretending those principles are relevant when you're deep in the weeds. Ironically, their attempt to paint these practices as sins is just revealing how little they know about writing extremely performant code. You tell beginners at C++ not to use global variables early on, because you want to teach them patterns like RAII, or teach them about constructor order. You tell beginning programmers to not repeat code so it's easier for them to debug, because they don't yet know about the deep underlaying architecture to understand how to utilize cache. The things they are citing are training wheels you take off to specifically write much more performant code.