how do you identify what are the  preprocessor and macros in c program  - Page 1
Forum section: electronics / general

author: Dadu@
author_rank: Contributor
timestamp: March 03, 2022, 08:29:44 am
content: Hi,I don't understand difference between preprocessor and macros in cprogramming language after reading material on internetI have written following code and I think value is preprocessor directive. compiler sustitute value 1 with textCode:#include<stdio.h>#define value 1#define add(y) y + 1int main (){int x = value;int y = 5;printf("x = %d \n", x);printf("y = %d ", add(y));return 0;}x = 1y = 6What is add(y) y + 1 ? Is it macros ?how do you identify what are the preprocessor and macros in c program ?

author: sleemanj
author_rank: Super Contributor
timestamp: March 03, 2022, 08:46:10 am
content: It's "preprocessor macro", a macro handled by the preprocessor. They are not different things.

author: ledtester
author_rank: Super Contributor
timestamp: March 03, 2022, 09:49:22 am
content: The short answer is that there is no easy way to tell if a symbol refers to a macro or not.You basically have to do what the C-preprocessor does... read all of the code that occurs before the use of the symbol and see if there are any #defines for that symbol.In a lot of cases authors will use all upper case for macro names -- e.g. FOO(...) refers to a macro named FOO and not a function. A lot of constants in the C standard library are implemented this way, e.g. EOF, the SEEK_* constants, ... On the other hand, there are also functions (or things you would expect to be a function) which are implemented as macros on some systems -- e.g. getc().Macros are a relatively simple mechanism which allowed early C programmers to work around the limitations of the compiler. Nowadays in many instances there are much better ways to accomplish what macros were used for in the past. If you google "why macros are evil" you'll find discussions like this:https://stackoverflow.com/a/14041847/866915

author: golden_labels
author_rank: Super Contributor
timestamp: March 03, 2022, 10:52:20 am
content: Unless someone used a preprocessor wrong,(1)for practical purposes it doesn’t matter if something is a macro expansion or an actual function call. So you may continue making a call without ever knowing if it’s really a call or text substitution. You should not assume either anyway, because it may change with another release of some library.One thing you must understand and remember, when writing your own macros, is that the preprocessor is dumb text substitution. It has no idea about C syntax: it just replaces sequences of characters in code.As for satisfying your curiosity and help with debugging, bothgccandclanghave the-Eoption. It stops the compilation process after the preprocessing stage and spits out a preprocessed file without doing anything else. The output is usually messy, as it’s not meant to be regularly used by humans, but debugging at this level happens to be ugly.(1)Which may include using it at all.

author: Dadu@
author_rank: Contributor
timestamp: March 03, 2022, 01:17:13 pm
content: Quote from: golden_labels on March 03, 2022, 10:52:20 amI am using windows 10 operating system. What is command for winows

author: grumpydoc
author_rank: Super Contributor
timestamp: March 03, 2022, 04:06:58 pm
content: Quote from: Dadu@ on March 03, 2022, 08:29:44 amBe careful writing function-like macros, and don't do it as in the example above.Macros are pure text expansion, which means that an unprotected argument can interact with operator precedence rules - eg if someone using your macro writesCode:y = 6;x = add(y)*4;They might be quite surprised that x ends up as 10, not 28 because it expanded toCode:y = 6;x = y + 1 * 4;So always put parentheses around macro arguments - i.e write#define add(y) ((y) + 1)There are, however lots more traps for the unwary when writing macros.

author: westfw
author_rank: Super Contributor
timestamp: March 04, 2022, 03:24:58 am
content: QuoteIf a symbol is a macro, it will "disappear" in the -E output that people have been talking about.

author: golden_labels
author_rank: Super Contributor
timestamp: March 04, 2022, 05:52:03 am
content: Quote from: Dadu@ on March 03, 2022, 01:17:13 pmThere is no “command for Windows”. Compilers are not an inherent part of operating systems. The options you need depend on the compiler you use. If you are usinggccorclangunder Windows, it’s-E, exacly the same as elsewhere. If it’s some other compiler, consult the documentation for it. Or tell us what is the compiler — perhaps someone will able to give some hints.

author: Berni
author_rank: Super Contributor
timestamp: March 04, 2022, 06:19:55 am
content: If you create it with #define then it is a preprocessor macro. Simple as that.Most decent C IDEs will also support coloring macros a different color (part of syntax highlighting)

author: brucehoult
author_rank: Super Contributor
timestamp: March 04, 2022, 06:26:55 am
content: Quote from: Dadu@ on March 03, 2022, 01:17:13 pmI'm so sorry.QuoteIf you use gcc or clang, then the same as anywhere else.I don't know if there are versions of gcc and clang that work in the DOS command line -- probably -- but you can certainly use them if you install WSL or cygwin.I believe Mingw-w64 is a port of gcc that can create Windows applications. I'm not sure whether it runs under DOS or in cygwin etc.

author: golden_labels
author_rank: Super Contributor
timestamp: March 04, 2022, 07:00:28 am
content: Quote from: Berni on March 04, 2022, 06:19:55 amDo you seriously think they ask about detecting macros they themselves has written?

author: Rick Law
author_rank: Super Contributor
timestamp: March 04, 2022, 07:02:53 am
content: Quote from: grumpydoc on March 03, 2022, 04:06:58 pmGrumpydocpointed out a very important point with macros in his reply above. There is another related one caused by the macro string replacement:For a simple example, let say we have a macro to triple the value.#define triple(y) ((y) + (y) + (y))Now think about if you do this, this works fine:++x;// first increment the countz = triple(x);// set z = ((x) + (x) + (x))But if you increment the count as macro's parameter,xis incremented three times:z = triple(++x)// this set z = ((++x) + (++x) + (++x))So, remember unlike a function call, macro is a text string replacement. If in your macro you use the argument multiple times and that argument changes itself, the change will be done multiple times also.

author: Ian.M
author_rank: Super Contributor
timestamp: March 04, 2022, 07:17:22 am
content: @brucehoult,There's alsoTDM-GCCthat runs GCC natively on Windows, and lets you build native Windows applications using the MinGW runtimes.

author: grumpydoc
author_rank: Super Contributor
timestamp: March 04, 2022, 11:48:28 am
content: Quote from: Rick Law on March 04, 2022, 07:02:53 amAbsolutelyAnother problem with the example above is that you have no idea what z would end up as - there is no sequence point between the three increments of x so you don't know whether x or x+1 will be added together.This problem with double evaluation shows up in the "naïve" implementation of "MAX" as a macro - if you writeCode:#define MAX(a, b) ((a) > (b) ? (a) : (b))You might well run into this.gcc has some extensions which can help avoid this so you can writeCode:#define MAX(a,b) \({ \typeof(a) _a = (a); \typeof(b) _b = (b); \(_a > _b) ? (_a) : (_b); \})but I don't think that's portable and it is best to avoid anything which is not idempotent as a macro argument.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 04, 2022, 12:08:29 pm
content: Quote from: Rick Law on March 04, 2022, 07:02:53 amWorse: it invokes the dreadedNasal Demonsof Undefined Behaviour. You cannot apply pre- or post-increment or -decrement more than once to a variable in a single expression.Many C compilers do usually do what you expect without surprises – except when you enable higher optimizations, and the results start to differ!Thus, it is better to avoid that sort of a thing, and also enable compiler warnings (so the compiler will tell you if you accidentally do that). Even if a simple test shows that a particular version of a particular compiler seems to handle it right.

author: brucehoult
author_rank: Super Contributor
timestamp: March 04, 2022, 12:17:17 pm
content: Quote from: grumpydoc on March 04, 2022, 11:48:28 amJust confirmed that works in Clang as well as gcc.How much more portability do you need? :-)gcc supports all the old historical stuff, and LLVM supports all the new stuff first and best.Well, except for the 8-bit CPUs covered by cc65 and sdcc. Hmm .. LLVM has a plain C back-end, which I'd presume you can pass the output of to those compilers...https://github.com/JuliaComputingOSS/llvm-cbe

author: brucehoult
author_rank: Super Contributor
timestamp: March 04, 2022, 12:24:51 pm
content: Quote from: Nominal Animal on March 04, 2022, 12:08:29 pmBut what is "handle it right"?If you do that with x initially 10, my assumption, as a compiler guy, is that "handling it right" would probably be 13 + 13 + 13. But you, on the other hand, might well imagine that "handling it right" would be 11 + 12 + 13.It's undefined. It could be either -- they are both perfectly consistent and logical. Or it could be something else, though it's harder I think to make a consistent argument for something else. Maybe 12 + 12 + 13 is arguable.In general, it's just a very very bad way to code.

author: brucehoult
author_rank: Super Contributor
timestamp: March 04, 2022, 12:41:08 pm
content: So I tried a couple of compilers on:Code:#define triple(x) x+x+xint foo(int n){return triple(++n);}clang on my Mac gives:Code:0000000000000000 <ltmp0>:0: 08 04 00 0b add w8, w0, w0, lsl #14: 00 19 00 11 add w0, w8, #68: c0 03 5f d6 retSo, that's returning 3*n + 6, i.e. for n=10 it's 11+12+13.gcc on x86 Linux gives:Code:0000000000000000 <foo>:0: f3 0f 1e fa endbr644: 8d 44 7f 07 lea 0x7(%rdi,%rdi,2),%eax8: c3 retqThat's 3*n + 7, so actually for n=10 that's 12+12+13.gcc for risc-v gives:Code:0000000000000000 <foo>:0: 0025079b addiw a5,a0,24: 0017979b slliw a5,a5,0x18: 250d addiw a0,a0,3a: 9d3d addw a0,a0,a5c: 8082 retSo that's 2*(n+2) + (n+3), or 3*n + 7, consistent with x86 gcc.I'm glad I said 12+12+13 is arguable in my previous post! That was based on the idea of evaluating side effects of each operand to a binary operator (or function) just before applying that operator (or function), and leaving side-effects on arguments of other operators until they were about to be evaluated.

author: DiTBho
author_rank: Super Contributor
timestamp: March 04, 2022, 01:03:12 pm
content: Let's say it simple and concise:don't use macro. Never.edit: bold

author: Ian.M
author_rank: Super Contributor
timestamp: March 04, 2022, 01:17:03 pm
content: That's overreacting. If you are writing 'vanilla' ISO C compliant code even MISRA hasn't gone as far as totally banning function-like macros. C++ code is a different matter as it has better ways of achieving a similar result.Ref:MISRA C:2004, 19.7 - A function should be used in preference to a function-like macro.MISRA C++:2008, 16-0-4 - Function-like macros shall not be defined.MISRA C:2012, Dir. 4.9 - A function should be used in preference to a function-like macro where they are interchangeable

author: grumpydoc
author_rank: Super Contributor
timestamp: March 04, 2022, 01:26:49 pm
content: No need to shout.I wouldn't go that far.However, it is reasonable to say that inline functions and modern complier options render a lot of macro use unnecessary, and the rest implementable in safer ways than times past.Perhaps better to say - don't use any language feature without having taken time to understand it.

author: DiTBho
author_rank: Super Contributor
timestamp: March 04, 2022, 01:45:25 pm
content: Quote from: grumpydoc on March 04, 2022, 01:26:49 pmPrecisely.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 04, 2022, 04:31:44 pm
content: Don't useanythingyou don't know how to use.C does not have templates, so macros are used forgeneric programmingormetaprogramming. Sometimes this is a lifesaver when it comes to readability, writability and maintainability of code bases. Yes, we all know the preprocessor sucks, and there are a few catches, you just need to know them:* for function-like interface, need to wrap inside do{} while(0), which looks odd when you see it for the first time* arguments must be in (parenthesis).Replacements are not without catches, either. Inreal world(ignoring dreams, hallucinations, etc.), the replacement for a macro means a non-portable attribute/pragma thing, forcing inlining of the function. Also, real-world experience shows that people who intend to do that, do not do that.Yet reality also shows that people often just forget to qualify their "private" functionsstatic. Mistakes happen. This does not mean that you should not use functions.

author: grumpydoc
author_rank: Super Contributor
timestamp: March 04, 2022, 04:58:39 pm
content: Quote from: Siwastaja on March 04, 2022, 04:31:44 pmSage advice, but obviously you generally need to use a thing to learn how to use it better.QuoteOnly multi-statement macros need this trick.The problem is that if you define a macro such asCode:#define do_a_and_b(x, y) \a(x,y); \b(x,y)you have a problem if you later writeCode:if (test)do_a_and_b(x, y);because this is going to expand toCode:if (test)a(x, y);b(x,y);The problem here is that b(x,y) will be called whether test is true or not - which is almost certainly not what the user of the macro expected.You could make the two statements into a blockCode:#define do_a_and_b(x, y) {\a(x,y); \b(x,y); }that does fix the "if" problem but causes a syntax error if you add a semi-colon after the macro call.Wrapping the block in do {...} while (0) gives a single block of code (which executes once)*and*allows a trailing semi-colon after the macro call without inducing a syntax error.

author: golden_labels
author_rank: Super Contributor
timestamp: March 04, 2022, 08:24:30 pm
content: DiTBho: no need to shout.As for the advice itself: you don’t have any choice. Not unless you want to stop using any library, including the C standard library.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2022, 12:08:55 am
content: Quote from: DiTBho on March 04, 2022, 01:03:12 pmDisagree.I am 100% convinced that the preprocessor is THE reason that hacky ugly C won out over functionally-equivalent but more "pure" languages such as Pascal.The preprocessor, skilfully used, enables extreme portability of code between very different systems, while keeping the main body of the code compact and readable.As an example of proven extreme portability over 30+ years and dozens of different systems, I present the Boehm GC:https://github.com/ivmai/bdwgc/blob/master/include/private/gcconfig.h

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 05, 2022, 02:30:10 am
content: Quote from: brucehoult on March 05, 2022, 12:08:55 amI agree with that. And not just for portability. It simply allows to avoid code duplication and makes modifications easier - that goes beyond portability.Sure it's simple and raw. With potential pitfalls. But very flexible. Most attempts at replacing it with a "cleaner" approach for metaprogramming (such as C++ templates, or various kinds of so-called "hygienic" marcro systems) have usually led to monsters to just be able to compete with the flexibility. Sure they are safer, more elegant ... etc... but to allow the same amount of flexibility, they inevitably need to grow to untractable monsters. And with C++, you still see some amount of preprocessor being used.While the simplicity of the C preprocessor (like the simplicity of C) can be "dangerous", it's also a benefit. As long as you know how it works (and it IS simple), looking at a macro definition (unless it's absolutely horrible, like obfuscated C contest-worthy) will tell you how it expands rather easily. The same is not necessarily true for complex template stuff.Sure there ARE horrific uses ot the preprocessor (as well as horrific uses of any language), but that doesn't mean it's bad or should be avoided at all costs.As to Pascal, I think it was missing a bit too much - at least in its original form - to be really usable for anything either moderately complex (it didn't have separate compilation or modules!), or moderately low-level. Not just a matter of preprocessor here. So in the early 70's, not sure Pascal would have been able to "compete" even if it got a preprocessor.Later variants of Pascal got a lot more features, so that's a different story. But it was too late.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2022, 02:59:37 am
content: Quote from: SiliconWizard on March 05, 2022, 02:30:10 amSure, the very first version was too limited. But it quickly got extended and by 1977 or 1978 things such as UCSD Pascal and VAX Pascal were completely suitable for both systems and application programming. Apple Lisa and then Mac were programmed in Pascal (including all of the OS that wasn't in assembly language). I believe the same goes for early Windows.I don't think C was at all available or popular outside of Unix until 1985 or 1986. I never used plain C at all in those days -- I went straight from (Object) Pascal to C++ in 1989/90.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 05, 2022, 03:41:01 am
content: And there was Turbo Pascal. Which did a lot to make Pascal popular for a while.I don't know about very early Windows, but the Windows API that I've run into (from Windows 3.1 to... current) has always exposed C interfaces. But I seem to remember that the calling convention of a lot of the API was actually Pascal - so that may come from the early days, and you may be right.As I remember, for "general-purpose use", C started to be talked about in the late 80's indeed. I remember computer magazine articles, from that period (maybe 87, 88) that talked about C as the language you should start taking a look at...C was still popular as a language on Windows until mid to late 90's. Remember the famous Petzold's books.But from say mid 90's to today, I think the *popularity* of C has been mostly due to Linux on one hand, and embedded dev on the other hand.

author: Ian.M
author_rank: Super Contributor
timestamp: March 05, 2022, 04:12:14 am
content: I hadHitechHisoftC on my ZX Spectrum back in 1984. IIRC it didn't play well with the ZX Microdrives (Sinclair's attempt at random access storage using an endless tape loop in a cartridge somewhat similar to an eight track cassette but smaller than a thin matchbox). Then I bought a 68000 C compiler for my Sinclair QL in '87, and disk drives as well because compiling from Microdrive was painfully slow and somewhat unreliable, and for part of 1990 I was employed writing a graphical scientific application in Microsoft C 6.0 to run under DOS and Windows 2.0. I don't think I was a particularly early adopter as I know a number of universities were teaching engineers C programming by the mid '80s.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2022, 05:52:24 am
content: Quote from: Ian.M on March 05, 2022, 04:12:14 amThat would have been on CP/M?I didn't have much experience of CP/M except for a DEC Rainbow in 1984 (which only had Turbo Pascal that I recall), then the CPC664 a couple of years later. But it was pretty familiar as I'd previously used DEC's RT/11.Oh! I also did a little consulting job helping some engineer get a printer working on a Kaypro. That would I think have been summer 83-84. So my first experience of CP/M.

author: Ian.M
author_rank: Super Contributor
timestamp: March 05, 2022, 08:13:05 am
content: Sorry about the brain-fart. I hadHisoft Con the ZX Spectrum, which compiled from cassette tape or a RAM buffer. As the ZX Spectrum didn't have a cassette control interface, compilation from tape involved a lot of noting of tape counter numbers, rewinding, and start/stopping the tape as directed! I later got the +3 version which had disc support. My uncle was the CP/M wizard in the family, and ran a maxed out Amstrad PCW, and in the end, a hard drive on it before he moved onto PCs.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 05, 2022, 11:10:59 am
content: Quote from: golden_labels on March 04, 2022, 08:24:30 pm... or build a massive NIH cathedral with new C standard library, complete tooling, even compilers written from scratch or modified ("hacked"), then make this a company policy, so that maybe 5-10 people on the Earth follow this new C-like language, which doesn't even allow * and & for pointer syntax but replaces it with something else. Then start filling threads giving others advice based on this internal paradigm, 98% of the time completely "forgetting" to mention this has nothing to do with normal C, causing massive confusion to everyone.In other words, I applaud complex and interesting custom solutions; complete descriptions thereof even more; but I hate games like this.

author: grumpydoc
author_rank: Super Contributor
timestamp: March 05, 2022, 12:25:17 pm
content: I have to say that I largely agree with SiliconWizard's analysis. C was popular because it was simply easy to write code in, at almost any level of the system from almost bare metal to complex end user systems and everything between.It was also found on everything from 8-bit CPUs to mainframes.It helped that it was a simple, but elegant language, easy to learn and even master but with distinct "depth" when needed.Obviously it was not perfect, quite a few features were essentially missing from the language and had to be handled by system libraries and it is safe to say that it bequeathed to the software industry whole new classes of coding errors.But it remains my favourite language.C++ in particular has become too complex - indeed had become too complex around the time I left the software industry in the early 2000's and has only got worse.

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2022, 01:29:31 pm
content: Quote from: brucehoult on March 05, 2022, 12:08:55 amYour opinion, bus sorry, I don't agree with that.For me, C flexibility with "data-struct" and "data-union" coupled with more powerful "pointer arithmetic" is one of *THE* reason whey C is better than Pascal in this specific cases, as well as Pascal, Modula2 and Oberon are better about making a project modular. With C ... it's rather impossible.--Anyway, I'm more interested in being able to debug and test the code, thereforemacro represent a serious problem(especially for team-projects) because1) specifically because macro have no body and no type (and no namespace)2) so (especially on the ICE side) the can be easily misused3) and - worse still - sometimes they expand into very complex code4) that can be difficult to identify and understand in the preprocessed file5) also it is easy to make error-prone code in macros6) and it's impossible to step-in a function-like macro because it's not a true-function7) so it's impossible to make automated test-cases and automated coverageIn short, I don't like Macro because I cannot debug them, while for sure they can mess up your day, and even if you take the time to fix it, well rationally it's unacceptable that I need to manually care manual testing points with an high probability of being error-prone points instead of safely invoking automating testing tools.

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2022, 01:42:38 pm
content: Quote from: SiliconWizard on March 05, 2022, 02:30:10 amDO178C says they must be avoided at all costsuntilyou have a test-case-plan to test your code. Which implies ***you*** have to write manual testing points since you cannot debug Macro.What makes me annoyed here is that Macro are like public toilets: everybody wants to use them but nobody wants to clean.

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2022, 01:53:46 pm
content: Quote from: Siwastaja on March 05, 2022, 11:10:59 amThis must be referred to my comments on my builder, which was completely unrelated to the Clang bug because those lines of C show the same defect even with standard C89/C99.Ok, I made the mistake to quickly test them with what I had on my hands, but why are you still here reproach me it was somehow confusing? and can't I express what I honestly think from 25 years of professional programming experience?I won't make the same mistake in the future. I promise.

author: Dadu@
author_rank: Contributor
timestamp: March 05, 2022, 05:43:23 pm
content: Quote from: brucehoult on March 04, 2022, 06:26:55 amone text file generates after running command. gcc -E hello.c > hello.txtCode:#include<stdio.h>#define add(y) ((y) + 1)int main (){int y = 5;printf("y = %d ", add(y));return 0;}text fileQuotewhat should be observed in this text file

author: golden_labels
author_rank: Super Contributor
timestamp: March 05, 2022, 06:32:34 pm
content: Quote from: Dadu@ on March 05, 2022, 05:43:23 pmThe third non-empty line from bottom.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2022, 11:14:03 pm
content: Quote from: DiTBho on March 05, 2022, 01:29:31 pmPascal has records, variant records, pointers, and the ability to cast between integers and pointers and find the size of objects. It has *exactly* the same capabilities as C in those regards.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2022, 11:22:13 pm
content: Quote from: DiTBho on March 05, 2022, 01:53:46 pmI'm not sure that's regarded as being a lot around here :-)What is "professional", exactly?I hadn't graduated yet (one more year...), but in 1982 I got paid to spend 10 weeks of my summer vacation writing COBOL (and a bit of FORTRAN) on a PR1ME minicomputer at the Whangarei City Council. I was the only person working on the project and it was successful.I'm far from the most experienced on this forum ...

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2022, 11:50:45 pm
content: Quote from: brucehoult on March 05, 2022, 11:14:03 pmPascal was my first programming language, and I know in TurboPascal v7 there is no "cast" feature which does this in the compile process like C. In Turbo Pascal there are standard procedures (built-in, or external) which *convert* a type to another type.That's how the first Pascal works. Call it "unchecked converter" (usually written in Turbo Assembly) and you get exactly what I have always tried to reproduce in every of C projects (in my case, written in C, but segragated outside the project space, so they won't be checked, that's why they are called "unchecked converters").If comparing pre-C89 to the first Pascal makes sense, then you also have to consider that the second one is more limited because it's more typed, and you cannot directly convert a record (struct) to an other record like with Unions in C, again you need to use "unchecked converters", and that's why I think people prefer C.Freepascal is the evolution of first Pascal, it adds new features and two flavors of typecasting - implicit typecasting and explicit typecasting, so now you also have - value typecasting - and - variable typecast - but if here it's like comparing c89 with something new, then for example you have to consider that when source’s range of value does not fit into the destination operand’s range, the compiler will not compile the program, unless it is instructed to ignore this, and that exactly what I means: still you desperately need unchecked converters to achieve your purpose.I think C people are not comfortable with this. When I switched to C I didn't feel it was limiting, but most of my friends left Pascal for this reason.

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2022, 12:21:29 am
content: Quote from: brucehoult on March 05, 2022, 11:22:13 pmI run software testing as part of the product life-cycle; "professional" means I won't get paid until I can prove with facts that a piece of code passes a series of test-cases.So when I look at a piece of code, I usually care about the possibility to write test cases by exploiting a debugging tool like the ICE: it's theoretically wrong (you cannot test the quality on the product, but) it is a sufficient condition to do my job with the best possible results with the least effort.If something can be debugged, it can be debugged automatically, then automatically tested with human supervision. I've been doing a lot of weird stuff over the past 15 years, recently I'm writing this kind of testing tools for a living.When I talked about my hack to Clang, well, that was a prototype that is paying off!

author: brucehoult
author_rank: Super Contributor
timestamp: March 06, 2022, 02:31:51 am
content: Quote from: DiTBho on March 05, 2022, 11:50:45 pmI've never used a version of Turbo Pascal as late as v7. I used 1.0 and you could certainly cast between pointers of varying types.Here is the manual for Turbo Pascal v3. It looks pretty much like what I remember from v1.0.http://bitsavers.informatik.uni-stuttgart.de/pdf/borland/turbo_pascal/TURBO_Pascal_Reference_Manual_CPM_Version_3_Dec88.pdfMay I refer you to section 22.12.2 "POINTERS AND INTEGERS"?QuoteAlso please see 22.8 ADDR FUCNTIONQuoteAlso please see 16.3.2.4.8. SIZEOF:QuoteTherefore you can write code such as the following:Code:vars : array[1..11] of char;p : ^char;begins := 'Hello World';p := Ptr(Addr(s) + 6 * SizeOf(char));WriteLn(p^);end... and you will see printed "W". And this will work no matter whether Char is 1 or 2 or 4 bytes.Pascal is functionally *exactly* the same as C in this regard. The only thing different is the exact syntax for achieving it.I didn't do any DOS or Windows programming, only Apple ][, then PDP-11/VAX and CP/M, and then Macintosh and Unix. EVERY Pascal I used had the ability to do this. The only difference I recall is some used @ instead of Addr.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 06, 2022, 03:04:53 am
content: Oh yeah, now I remember this in TP 3.0 that I used on CP/M. You could even insert assembly code directly in procedures and functions - there was no internal assembler, so you had to list the opcodes, but there was a syntax for putting the address of a parameter or variable directly in the opcodes stream.The only thing I was really missing in Pascal was the ability to pass functions and procedures as parameters/variables. (I think that was added in TP much later?)Of course, Wirth added that in Oberon (and maybe Modula, but I admit I don't know Modula well.)The other thing missing was separate compilation/modules (at least in TP 3.0), but this was added in later versions as "units", which were relatively similar to Modula and Oberon modules. Units were available in the first (and I think only) version of TP for MacOS, that I also used in the early 90's. It was a decent environment to program for MacOS back then. =)

author: brucehoult
author_rank: Super Contributor
timestamp: March 06, 2022, 04:01:04 am
content: Quote from: SiliconWizard on March 06, 2022, 03:04:53 amThat has *always* been in Pascal. Maybe TP didn't include it? Borland did have a habit of just leaving stuff out.See the railway track diagram for Parameter list on p355 of Wirth's 1976 "Algorithms + Data Structures = Programs", which includes "function foo : returnType" or "procedure bar" as items in a parameter list.http://www.cl72.org/110dataAlgo/Algorithms%20%20%20Data%20Structures%20=%20Programs%20[Wirth%201976-02].pdfThere is, obviously, an un-Worthian lack of type checking in this early version.Apple's 1980 Apple Pascal Language Reference Manual explicitly states on p87 that it differs from standard Pascal in NOT allowing procedures and functions to be passed as arguments.https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Software/Languages/Apple%20II%20Pascal/Manuals/Apple%20Pascal%20Language%20Reference%20Manual.pdf

author: Dadu@
author_rank: Contributor
timestamp: March 06, 2022, 08:33:51 am
content: Quote from: golden_labels on March 05, 2022, 06:32:34 pmhello.cCode:printf("y = %d ", add(y));textCode:printf("y = %d ", ((y) + 1));In text file body of add (y) executeBut still there's a lot confusion

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2022, 09:21:59 am
content: Quote from: Dadu@ on March 06, 2022, 08:33:51 amPrecisely. Confusion. Macros are confusing. What did I say from the start?W-H-A-T?!?

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2022, 10:02:08 am
content: Quote from: brucehoult on March 06, 2022, 02:31:51 amI didn't say there are no pointers, I said there is no easy-Unions like in C, and in general, in Pascal you need more effort to get the same result.A Pascal-union-like is called "case inside a record", it makes it possible to give a variable multiple types. In this example w1, w2, w3 are stored at the same location in memory:Code:OType = (type1, type2, type3);OMe = recordcase myType: OType of <-------------- this is a union-like in Pascaltype1: (w1: Integer);type2: (w2: Integer);type3: (w3: Integer);end;It's not safe, there are Pascal implementations that don't check the simple semantic correctness(1), if you want a "typesafe union", you should use "inheritance", which is a plus for me because it forces you to think twice about what you are doing with the result that it usually makes things cleaner, but not for most people who have switched to C.Those two standard functions Ord() and Ptr() are exactly what I was talking about when I write "unchecked converters". It's a term I invented to describe things that are somehow part of the language, like "sizeof()" is part of the C language, but they are not written with the same language they belong to as operators/functions, but rather with an external language, usually assembly.(1) certain implementations don't detect accessing an inactive variant in a case blocks in variant records.Code:varO: OMe;beginO.myType := Type1;O.w2 := 666; <-------- There is no w2 for Type1, w2 belongs to Type2!end.- ISO 7185 Standard Pascal implementations usually care about that- Turbo Borland Pascal usually don't care about that

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2022, 10:15:56 am
content: @Dadu@I usually use cpp *only* for two thingsto define the size of a static array.to define the version and revision of a moduleCode:#define pool_N 200pool_item_t pool;#define Ver "v1.0"#define Rev "revA"If you look at my topic on complex numbers, well ... this is a nice example of when I say that "macros are like public restrooms, everyone wants to use, nobody (me included) wants to clean". See, glibc adds a lot of Macro layers to describe different kinds of functions, which sounds good to listen to because you have "float atan()", "double atan()", etc ... "type_x func_y()" , but things get so messed up that gcc-v8-v11 is out of the box and nobody in Gentoo wants to clean it up because it would involve a patch to glibc, which is a prohibition since it's too fragile (if you break glibc, the whole system collapses) .And since I don't like to waste time on that, I had to create an ugly hack to bypass some of those Macros, so things are back working and I can complete my projects.

author: brucehoult
author_rank: Super Contributor
timestamp: March 06, 2022, 01:06:22 pm
content: Quote from: DiTBho on March 06, 2022, 10:02:08 amYes, I'm perfectly aware of Pascal variant records. I used Pascal professionally as my main language for about ten years.QuoteNeither are C unions. That's the whole point. You can use them for exactly the same tricks.In some Pascal implementations you have to change the selector field in order to not get an error when accessing an aliased field. So you change the selector. It never hurts to do so anyway.I theory, perhaps some conforming implementation could zero out the other fields when you change the selector, but I've never see that happen. The raw bits are still there, and can be accessed via the alternate field names.As I said, C and Pascal are almost totally interchangeable.Sometimes you need to type a little more code in Pascal but the generated machine code and runtime results are equivalent.By far the biggest difference is that C/C++ don't have lexically nested functions with the ability to access outer function local variables from inner functions -- even when the inner function is passed to a yet another function (e.g. qsort()).But gcc and clang implement that in C anyway, as an extension.Another difference is that Pascal typically allows you to directly do boolean AND, OR, bit set/clear/test on bit vectors of at least 256 or 512 bits, under the type "set of ...". In C you need to explicitly create and array of char or int (etc) and write some loops or div/mod and shift.Again, the generated machine code is exactly the same in the end.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 06, 2022, 05:52:06 pm
content: What exactly is an "easy union" compared to variant records?

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 06, 2022, 06:05:57 pm
content: I often rungcc -Wall -dM -Esource-files...| sortto obtain the list of all preprocessor macros that apply when compilingsource-files....I also use thePre-defined Compiler Macroswiki, to look for preprocessor macros that let me create portability workarounds or optimized versions for specific hardware/OS/compiler/C library combinations.As illustrated by the above discussion, there are strong opinions regarding preprocessor macros. Whether you can rely on them (consider e.g. C11 6.5.1.1_Generic()selections), or you need to avoid them, depends onexternalreasons. Those external reasons can be standards likeMISRA C, company or organizationcoding conventions, and so on.Because C itself does not force anything with respect to preprocessor macros, it is up to us humans to deal with it. The most common approach is to use all UPPERCASE names (with underscores _ replacing spaces) for only preprocessor macros. If you use an advanced source code editor, it can usually help with this kind of stuff.Me, I try to go with the principle of least surprise,unix philosophy, andPOSIX; the important/meaningful exceptions to the "uppercase thing is a macro; macros are in all uppercase" rule are so few one can actually remember them all:FILE(is a type and not a macro);getc() and getchar(), andputc() and putchar(), all four of which may be macros that evaluate the stream argument (the FILE pointer parameter) more than once. There are a few additional ones, but these five are the important ones.

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2022, 09:25:39 pm
content: Code:OType = (type1, type2, type3);OMe = recordcase myType: OType of //<-------------- this is a union-like in Pascaltype1: (w1: Integer);type2: (w2: Integer);type3: (w3: Integer);end;Code:varO: OMe;beginO.myType := Type1;O.w1 := 1; // this is ok!O.w2 := 666; //<-------- There is no w2 for Type1, w2 belongs to Type2!end.Code:typedef union{struct{uint32_t w1;} type1;struct{uint32_t w2;} type2;struct{uint32_t w3;} type3;} OMe_t;Code:void foo(){OMe_t O;O.type1.w1 = 1;O.type1.w2 = 666; // <-------- There is no w2 for Type1, w2 belongs to Type2!}Turbo Pascal v7 (embedded inside DoxBox on a Linux machine)Code:compiling foo.pas ... done(no error)C (Gcc on a Linux machine)Code:compiling foo.c ... failedfoo.c:25: error: 'struct <anonymous>' has no member named 'w2'Conclusion: unions in C are by - de fact - simpler to check in C than in Pascal.

author: brucehoult
author_rank: Super Contributor
timestamp: March 06, 2022, 10:22:29 pm
content: Quote from: DiTBho on March 06, 2022, 09:25:39 pmOK, so TP doesn't check the current variant. It's allowed to not check, but just to be (un)safe you can doO.myType := Type2before trying to access w2, and it will work also on compilers that do check.QuoteThis is stupid. Obviously you need to writeO.type2.w2 = 666if you want to get or set field w2.You can equally easily use variant records in Pascal and unions in C to do unsafe typecasting when you want to. Which is the point -- everything you can do in C, you can also do in Pascal.In fact Pascal has the advantage here because in C you can't tell which union member you should use.Let's add aprocedure printOme(O : Ome)and functionvoid printOme(OMe_t O)that print the correct current field in the data passed to them.(This is a dumb example because w1, w2, w3 all have the same type, so it doesn't matter, but whatever ... assume one of them is a float and maybe another is a char)In Pascal:Code:procedure printOme(O : Ome)begincase O.myType oftype1: WriteLn(O.w1);type2: WriteLn(O.w2);type3: WriteLn(O.w3)endendvarO: OMe;beginO.myType := Type1;O.w1 := 1;printOme(O);O.myType := Type2;O.w2 := 666;printOme(O);end.And in C...Code:void printOme(OMe_t O){// ?????printf("%d\n", O.type1.w1);printf("%d\n", O.type2.w2);printf("%d\n", O.type3.w3);}void foo(){OMe_t O;O.type1.w1 = 1;primtOme(O);O.type2.w2 = 666;primtOme(O);}How do you decide which one to print in the C version?Answer: you can't.Of course, since Pascal and C are equivalent, you *can* do this, with extra work, by defining anOTypeenum and wrapping the union in a struct with an extramyTypefield. And then in printOme do a switch on the myType field.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 07, 2022, 01:34:39 am
content: Quote from: brucehoult on March 06, 2022, 10:22:29 pmOf course. That's what you usually do one way or another, unless you love shooting yourself in the foot.

author: brucehoult
author_rank: Super Contributor
timestamp: March 07, 2022, 03:03:17 am
content: Quote from: SiliconWizard on March 07, 2022, 01:34:39 amExactly.And in case anyone wants to say "Oh, but Pascal and C aren't equivalent because if you somehow know from some other means which variant is the current one then you don't have to have the wasted storage for the type tag field".No .. in Pascal the type of the selector is required when you declare the variant record type, but the selector name (and the colon) are not. In which case it isn't stored.In general, I stand by my assertion that the standardised preprocessor is the only important distinguishing feature between Pascal and C.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 07, 2022, 06:35:43 pm
content: Quote from: brucehoult on March 07, 2022, 03:03:17 amWell, I don't quite agree, but that's a matter of perspective.I mentioned functions/procedures as parameters, you corrected me saying that they were in the Pascal definition, and I'll believe you. I didn't check. (I admit I never read the official specs of Pascal, contrary to the later Oberon and even - out of curiosity - Modula 3.) I admit I mostly used TP back then, and it didn't implement them. So anyway, let's cross that out.But there was the matter of separate compilation. I don't think the original spec defined that, but apparently UCSD Pascal was the first defining "units", so that part was long existing too. (And in a better form than just includes.) TP didn't implement this until later versions.So yeah, not much left missing? IIRC, you could even do conditional compilation in most Pascal compilers with "directives".Now, outside of unions (for which I agree with you), C still was easier to use for accessing "memory" through structures than Pascal.I don't think you could, for instance, define the memory location of a record and then access its fields to access particular memory locations as you could do with C. While the equivalent in Pascal was possible, it was not as "elegant" (that may be a matter of taste.) But here again, maybe you have a better memory and command of Pascal, and maybe that was just as easy?Ultimately, as for later Wirth languages, the real problem was not the language itself, but the lack of existing tools for a large range of platforms.The reason for this is a complex one - we can refer to our discussions about what makes a language popular or not. Its technical merits are most often marginal for explaining popularity.An interesting example was Modula-3. It was *the* descendant of a wirthian language that was carefully defined by a group of industry professionals. It was fully usable, and in many aspects, would definitely still be. The tools were very few though. CM3 which was one of the few has known some kind of rebirth:https://github.com/modula3/cm3One could also say that Ada is a descendant of those wirthian languages, and Ada is still alive and kicking, even though it's still in niche applications.

author: DiTBho
author_rank: Super Contributor
timestamp: March 07, 2022, 07:28:16 pm
content: Quote from: SiliconWizard on March 07, 2022, 06:35:43 pmPrecisely! Plus, easier for the ICE, therefore easier for debugging, which is what I care most about everything.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 07, 2022, 08:12:18 pm
content: Quote from: DiTBho on March 07, 2022, 07:28:16 pmTo be fair - I don't remember all the details of Pascal, haven't used it in ages, so I need to brush up! Taking what Bruce said:QuoteDefining a pointer to a record at a specific address should be trivial in Pascal. So, contrary to what I said, this should be no problem at all.Debugging is a different issue if you consider tools. The fact there were more tools for C does not mean C was better than Pascal. It's just a popularity problem, as I mentioned earlier, not a technical issue.So now, I'll just have to agree with Bruce. There was no sizeable difference between Pascal and C, apart from the preprocessor. The only difference that really mattered for developers, as you yourself noted, were the tools available. But the language itself certainly never prevented such tools to exist. A number of compilers, TP being the most popular, actually lacked some features because they were meant to be simple - TP 3.0 just fit within about 30 KBytes on CP/M, with an integrated editor!Getting to understand why some languages become more popular than others is a complex matter, which we have talked about in numerous threads already. The causes are complex to understand, and again the technical merits are often just a marginal point. But once a language becomes popular, the ecosystem grows, there's a lot more tools, libraries, etc, available, and so that reinforces the popularity.One point that could explain the lack of debugging tools for Pascal, even back at the time when it was moderatly popular, may also have something to do with a lack of... demand. Not to sound corny, but possibly stuff written in Pascal required a lot less "debugging" with low-level tools than stuff written in C. The fact you yourself once had this particular need can by no means be generalized.

author: Rick Law
author_rank: Super Contributor
timestamp: March 07, 2022, 09:18:16 pm
content: I think by today hardly anyone develop commercial systems using Pascal. By commercial systems I mean anything used in a product or business. So, comparing Pascal and C is rather academic now.Yeah C is not safe. A hammer is not safe when used wrong. We should think of it as the need to improve the quality of the users (programmers) rather than putting yet another layer of steel on the boots to prevent the user from shooting himself/herself on the foot.So allow me to remind folks of an old saying: "When it is absolutely idiot proof, it would be so overburdened only idiots will use it..."

author: brucehoult
author_rank: Super Contributor
timestamp: March 08, 2022, 12:51:13 am
content: Quote from: SiliconWizard on March 07, 2022, 06:35:43 pmYes, that dates from 1977. VAX Pascal did something similar -- VMS allowed you to do separate compilation and mix object files from different compilers and languages right from the start.QuoteYes. Not my experience was with DEC and Apple computers. I didn't use MS-DOS or Windows at all.Apple Pascal (UCSD) and VAX Pascal had %include but not conditional compilation.Apple Lisa Pascal had compile-time defines and conditional compilation. I've screenshotted the relevant page from the manual:https://pbs.twimg.com/media/FNSYsAuaAAAUbhp.pngFull manual athttps://archive.org/details/bitsavers_applelisawl3.0ReferenceManual1984_16927177/page/n151/mode/2upPascal compilers on the Macintosh followed Lisa Pascal. Early Macintosh apps (and the OS) were written and compiled on Lisa computers, using Lisa Pascal. So there is at least Macintosh Pascal (interpreted), THINK Pascal, MPW Pascal, Metroworks (CodeWarrior) Pascal. All maintained close source compatibility with Lisa Pascal, including conditional compilation.There was a short-lived Mac version of Turbo Pascal which I believe only had include files not conditional compilation. Manual here:https://winworldpc.com/download/73283e1b-9e4b-11e8-893a-fa163e9022f0What was missing was macros, and in particular function-like macros.QuoteNot sure what you mean there. I believe I already showed how to do that in ...https://www.eevblog.com/forum/programming/how-do-you-identify-what-are-the-preprocessor-and-macros-in-c-program/msg4045750/#msg4045750That was making a pointer to a char point to an arbitrary place in memory, but it's just the same with a record.

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2022, 08:31:07 am
content: Pointer to arbitrary place in memory work very good with the mentioned "unchecked converters". I haven't yet played with the Mikroe's Pic-Pascal, but years ago I usedTurbo51, a Pascal compiler for intel51 chips in expanded mode (full 64Kbyte addressing space) on a weather station(1) powered by an enhanced 51 chip.Turbo51 offered excellent code generation an optimization, it didn't offer any ICE support only source-level debugging with OMF object file, it means you have to pay for static-debugging tools, which is ok and fair, just a note: the weather-station-project was only partially written in Pascal, all the memory-side things (so through user-defined "unchecked converters") were written in Assembly.

author: westfw
author_rank: Super Contributor
timestamp: March 08, 2022, 11:07:36 am
content: Is “separate compilation units” really considered a feature of the “language”?I would have thought it orthogonal, the way some assemblers support a linker, and some don’t.I guess if you want to have the strong typing and range checking of something like pascal, you need an equivalent of “extern” that conveys all that in the absence of full source?

author: brucehoult
author_rank: Super Contributor
timestamp: March 08, 2022, 12:37:42 pm
content: Quote from: westfw on March 08, 2022, 11:07:36 amCompilers for languages such as Pascal and the Modula family generally output two things: 1) an object file for the executable code, and 2) a "definition" file that contains all the type information for globally visible declarations. A binary equivalent of a C header file. Or pre-compiled header file.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 08, 2022, 05:58:30 pm
content: Pascal units are like modules for other languages, they are DEFINITELY a feature of the language. Modules in general are not just object files that you happen to link.For C, it could be argued that separate compilation is less of a feature of the language, but that still wouldn't be entirely true. The language has to define that global symbols (that aren't static) are "exported" in object files, otherwise separate compilation would never work. So even for such a basic support as in C, it IS a feature of the language.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 09, 2022, 05:57:39 pm
content: Quote from: brucehoult on March 08, 2022, 12:51:13 amYes, I corrected that in a later post.All in all, as I said, I think the restrictions were more due to available tools and what they implemented than to the language itself.And there's been some kind of "battle" between C-like languages and "wirthian" languages for several decades. (I consider Ada a wirthian language.)Common points made "against" wirthian languages is that they are seen as more "verbose" and more "rigid". Of course, some will see that as meaning more readable, more maintainable and "safer", while many tend to see this as just plain annoying and counter-productive. The latter seem to be the majority these days, but interestingly, those "arguments" are almost entirely subjective, while the former have at least some objective basis to them.

author: westfw
author_rank: Super Contributor
timestamp: March 09, 2022, 10:33:06 pm
content: QuoteIt always worries me when the distinction between "a language as defined" and "particular implementations of the language" becomes blurred. "BASIC is a fine language with modern structured programming constructs, compiled code, and optional line numbers - I don't see what people are complaining about!"Pascal as defined by Wirth was perhaps so obviously useless that no one ever tried to develop actual products with it; it remained (?) confined to the educational uses it was aimed at. I mean, no equivalent of fopen()?? "we'll just leave that all the the JCL?" (but the BNF for the core lanaguage was sure pretty!)One of my college projects involved adding formatted output to the Pascal compiler, because a lot of programming back then ended up wanting to output nice neat tables of numbers, just like Fortran could make. There was never a thought that this could be written in Pascal itself, because user-level Pascal procedures could have a variable number of arguments (even though they were used by the Pascal IO procedures.)I guess all that got fixed in the various real-world compilers. Which is fine, but...OTOH, I'm not sure that early C ever had a clear "definition." By the time it escaped into the world at large, it instead essentially had a "reference implementation." If you wanted to be a successful C compiler, you had better implement things the way the PDP/11 Unix Compiler did it. "We'll define it later." (and they did.) (I particularly remember the early implementations of VARARGS: "well, we know that the caller put all the arguments on the stack in THIS order, and everything is promoted to an int, so if we take the address of the last (or first) argument, we can point to things past that and there will be the additional arguments!")

author: brucehoult
author_rank: Super Contributor
timestamp: March 09, 2022, 11:41:14 pm
content: Quote from: SiliconWizard on March 09, 2022, 05:57:39 pmYes, I've seen that now.QuoteI don't "get" such battles. I'll very happily use either.What annoys me much more is all the languages that decided they should look like C while having vastly different semantics to C. Java and JavaScript and C# being the obvious offenders.Whatever is good about C, it's not the syntax, and most especially not the syntax of declarations.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 10, 2022, 12:33:11 am
content: Quote from: brucehoult on March 09, 2022, 11:41:14 pmOh, I do agree with that. But syntax is part of a language, and a significant part of it nonetheless. And, give C a pascal-like syntax, and many people will likely shy away from it, even if you don't change a single feature except the syntax.Language designers deciding to make them look C-like syntax-wise is a whole part of that IMHO. It looks like a vast majority of developers prefer that kind of syntax precisely because it is seen as "non-verbose". Heck, if you look at even more recent languages, such as Rust, they seem to go out of their way to further shorten keywords to apparently make them look even less verbose. They also want to get rid of statement terminators (see Go and Swift?). Because even that looks like too much. Etc. This is my view of it, but it seems rather apparent that there is a commonly shared obsession with reducing the "verbosity" of programming languages, sometimes to a ridiculous degree.

author: DiTBho
author_rank: Super Contributor
timestamp: March 10, 2022, 10:37:11 am
content: Back to #define ... OMG u-boot has four layers of nested #define#define A ... // from (file1, and don't forget to check the right #ifdef, or perhaps it's the #else branch? )#define B A // from (file2, and don't forget to check the right #ifdef, or perhaps it's the #else branch? )#define C B // from (file2, and don't forget to check the right #ifdef, or perhaps it's the #else branch? )#define D C // from (file3, and don't forget to check the right #ifdef, or perhaps it's the #else branch? )#define again what is defined here of what is defined there of what /// I am lostThat is very confusing because hard to follow (-E doesn't save your days but it helps a lot) and I don't actually know what a line of code does. It's the pATA part because some pATA controllers work in legacy-mode (like ISA cards), some in PCI-mode, and some in PCI-mem-only.Two lines of C code cost me 6 hours of struggling, rather annoyingOcteon MIPS64 has something similar for their SoCs, and the Wr703 code made for Atheros is a full similar mess.I seriously hate nested #define, really, I promise I will hug a tree and walk barefoot, but don't do this! PleaZe

author: Siwastaja
author_rank: Super Contributor
timestamp: March 10, 2022, 02:31:05 pm
content: I don't understand why people do not follow normal indentation practices with the preprocessor.Nesting itself isn't a problem. This is unreadable as well:Code:void func(){if(asdf == 123){for(int i=0; i<42; i++){if(condition)break;}}}Yet people do exactly this with preprocessor. Except me, I follow normal indentation practices:Code:#ifdef THING#if 1==2void func(){...}#endif#endifLines get too long? #include things away.

author: brucehoult
author_rank: Super Contributor
timestamp: March 10, 2022, 11:04:05 pm
content: Yah, this is annoying.emacs by default does not indent preprocessor directives -- it forces them to NOT be indented.This can be changed by adding the following to your .emacs in the c-mode hook:(c-set-offset (quote cpp-macro) 0 nil)

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 10, 2022, 11:43:58 pm
content: Quote from: brucehoult on March 10, 2022, 11:04:05 pmI admit I usually do not indent preprocessor directives. It's out of habit entirely; probably from having been exposed to a lot of source code that did not indent them, early on. Also, some compilers did not like it, but that was probably a long time ago.That's less readable though, so I agree and will try to change habits.

author: DiTBho
author_rank: Super Contributor
timestamp: March 11, 2022, 12:18:42 am
content: Formatting the sources is not a problem, the problem isn't whether you indent or not, the problem is four bloody layers of definitions! One inside the other like a Matryoshka.I like soviet Matryoshkas, but only when they are made of wood and visually look like a babushka.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 11, 2022, 08:04:39 am
content: All software is layers after layers after layers. If you look at a video of cat dropping things from the table on Youtube, and count all levels of layers (all functions and ifs and elses) from the upmost level to the pixel drawing in the GPU HDL, you have possiblythousands. They are just... encapsulated.Four layers in itself isn't the problem. They should have done some form of encapsulation; utilize makefiles and separate .c files, or maybe just used #include better, or so on. You can totally do abstraction in preprocessor, and compilers can follow it in error messages etc. ("in macro XXX, included from file YYY...")And indentation helps for a few levels. But arguably, 4 levels of just preprocessor indentations is pushing it. Code ending up far right reveals it is too much. Solution is not to remove indentation.

author: DiTBho
author_rank: Super Contributor
timestamp: March 11, 2022, 09:21:03 am
content: Quote from: Siwastaja on March 11, 2022, 08:04:39 amSo you can compare *layers of code* (under control) with *layers of macro* (out of control, just text-replaced with text).

author: Siwastaja
author_rank: Super Contributor
timestamp: March 11, 2022, 06:00:34 pm
content: I don't understand the difference you talk about. Why macros are "outside of control"? What does this "control" even mean?Why can't you testbench the macros with test vectors?Compiler can decide to inline any function (even non-static!) without asking you, at all, for optimization, acting exactly like it was a macro.Sure, preprocessor is kind of its own language, and thus has its own footguns.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 11, 2022, 06:30:07 pm
content: Like tabs vs. spaces and brace style, macros are yet another of those hot topics.Some people having a problem with multi-level macros appears to be a common thing - I've heard that quite a few times.I do not quite get it either myself. As you said, like with general code, it's just a matter of writing readable and correct stuff.The benefit of writing multi-level macros is the same as using macros in general: avoiding to duplicate code by hand, and making some modifications much easier (when there is only ONE place where changes need to be made.)As Siwastaja said, if you're really unsure of macros - just write a set of tests for them. It's unusual (I've never done that myself and never seen it done directly), but it's definitely doable. Just write a series of tests invoking macros and the expected output, then invoke the preprocessor separately (all C compilers I've ever used could do this), and compare. It can be fully automated.There are well known "pitfalls" of macros due to the fact they are just text substitution. The first class of them appears when macro parameters are not all parenthesized. Just put parentheses around all parameters in macro expressions, and this issue disappears immediately. The other one, of course, is calling a macro with parameters that have side-effects, if said parameters are used more than once in a given macro definition. To mitigate this one, you can either make it a rule never to call a macro with parameters that have side-effects, or never write a macro that substitutes any of its parameters more than once. Done.

author: DiTBho
author_rank: Super Contributor
timestamp: March 11, 2022, 07:26:44 pm
content: Quote from: SiliconWizard on March 11, 2022, 06:30:07 pmUm like what? Qualcom's code? Denx's code? Atheros's code? Yes, macro avoid them to duplicate code by hand, but when you have to fix their code you cry up with dozen of order on Amazon ...What? Which orders? baskets of migraine pills, family packagesQuote from: SiliconWizard on March 11, 2022, 06:30:07 pmWhich brings us to what I wrote a page ago:I know I can write a series of tests, but guess what? Who do you think has usually to write those tests because other people simply don't care?Dude, when you have to fix a code like that and you're not getting paid for it, you don't really like wasting days and days on it because you don't understand what layers of macro do.

author: DiTBho
author_rank: Super Contributor
timestamp: March 11, 2022, 07:39:39 pm
content: Quote from: SiliconWizard on March 11, 2022, 06:30:07 pmNo, it's not a question of elegant code, but rather of having tools that understand and process the code so that you can do your job without constant headaches.

author: cfbsoftware
author_rank: Regular Contributor
timestamp: April 23, 2022, 10:08:55 pm
content: Quote from: Rick Law on March 07, 2022, 09:18:16 pmNot ISO Standard Pascal certainly, but Pascal with numerous extensions lives on in the commercial world in the form of Delphi:https://www.embarcadero.com/products/delphi