I once took an "Advanced C Programming" class (which would have been better named as "How to do OOP in a language never intended for it") where the instructor expressly prohibited the use of "*i++" and several other language elements because he thought they were confusing. I got into many arguments with the instructor throughout the course, and I figured I would get a poor grade, but he still gave me an A. My main disagreement with him was this: If the language elements are there and well defined, why prohibit their use? The course after all was "Advanced C", wasn't it?
That has been my argument for "preprocessor abuse" - there isn't such thing as preprocessor "abuse"[0], it is part of the language and provides some form of extensibility in a language with an already limited set of features.
If anything the preprocessor needs more features (let me include files from macros and do loops dammit :-P).
[0] ok, i can think of some uses that might count, like "#define BEGIN {", etc that serve no practical purpose, but i don't think anyone called these "preprocessor abuse".
m4 is a bit weird but if you can use that you can use any preprocessor - including a custom one.
The issue is that chances are said preprocessor wont work with editors and IDEs that can parse C to provide tools like syntax completion, jumping to definitions, etc - if anything you'd be lucky if you get working line numbers t use a debugger with.
"Programs must be written for people to read, and only incidentally for machines to execute"
-- Abelson & Sussman, Structure and Interpretation of Computer Programs, 1984.
It's possible to write English with bad structure, clumsy metaphors, obscure vocabulary, and non-non-non-usual idiosyncrasies. And other people might be technically capable of understanding it if they really want to, and try hard enough.
After all, the language elements are there and well-defined, so why would anyone ever complain about "bad" writing?
(Out of curiosity, do you object to people who say the use of "goto" should be seriously restricted, or even prohibited, in most programs? Do you specifically use gotos to make the point that they can still be be useful and productive? The language element is there and well-defined.)
I've used a goto in production code twice in >30 years. In both cases it was the right thing to do, and it had more to do with hardware elements and mission assurance than with software engineering.