Help with C language macro stringification  - Page 1
Forum section: electronics / general

author: Back2Volts
author_rank: Unknown
timestamp: July 28, 2017, 02:06:54 pm
content: I have this macro which works fine#define LA_TRACE_PORT_DR (CYREG_PRT0_DR)but I would like to use a define for the "0", so I am looking for something like the following (with proper syntax)#define LA_TRACE_PORT_NUM "0"#define LA_TRACE_PORT_DR ("CYREG_PRT#LA_TRACE_PORT_NUM#_DR")What is the proper syntax in the last two defines to come up with the equivalent of the first one? You can imagine that I have tried a few silly variations before I came to post here. I am not sure it makes a difference, but I am using gcc.Tony

author: cv007
author_rank: Frequent Contributor
timestamp: July 28, 2017, 02:20:32 pm
content: #define LA_TRACE_PORT_NUM 0#define _LA_TRACE_PORT_DR(n) (CYREG_PRT#n#_DR)#define LA_TRACE_PORT_DR(n) _LA_TRACE_PORT_DR(n)use-LA_TRACE_PORT_DR(LA_TRACE_PORT_NUM)You need the second define so LA_TRACE_PORT_NUM gets processed/reduced.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 28, 2017, 03:34:40 pm
content: Code:#define LA_TRACE_PORT_NUM 0#define CONCAT3(a,b,c) a##b##c#define LA_TRACE_PORT_DR_PROTO(x) (CONCAT3(CYREG_PRT,x,_DR))#define LA_TRACE_PORT_DR LA_TRACE_PORT_DR_PROTO(LA_TRACE_PORT_NUM)Usage (should print 15):Code:#define CYREG_PRT0_DR 15int main(void){printf("%d\r\n",LA_TRACE_PORT_DR);}

author: legacy
author_rank: Super Contributor
timestamp: July 28, 2017, 05:22:56 pm
content: (don't abuse the macro-processor)

author: SimonR
author_rank: Regular Contributor
timestamp: July 28, 2017, 10:18:44 pm
content: Quote from: legacy on July 28, 2017, 05:22:56 pmGood point, but its just so tempting

author: Back2Volts
author_rank: Unknown
timestamp: July 29, 2017, 03:42:15 am
content: Thank you guys. I have it working and I promise I will try to avoid macrosTony

author: SimonR
author_rank: Regular Contributor
timestamp: July 29, 2017, 10:18:33 am
content: Don't avoid them, just be careful how you use them.

author: Kalvin
author_rank: Super Contributor
timestamp: July 29, 2017, 11:13:58 am
content: You may want to familiarize yourself to X Macros:https://en.wikipedia.org/wiki/X_MacroCheck also the article references. X Macros are handy things to know. However, do not overuse them

author: Hypernova
author_rank: Unknown
timestamp: July 29, 2017, 12:39:00 pm
content: Quote from: legacy on July 28, 2017, 05:22:56 pmWhat good is power if you can't abuse it?

author: legacy
author_rank: Super Contributor
timestamp: July 29, 2017, 01:06:00 pm
content: Quote from: Hypernova on July 29, 2017, 12:39:00 pmWhat good is power if you can't abuse it?( eh, when are you in a rush, and ...you find that the macro processor has just done a messMay God save the Queen)

author: Hypernova
author_rank: Unknown
timestamp: July 29, 2017, 01:22:52 pm
content: Quote from: legacy on July 29, 2017, 01:06:00 pmHence you are supposed to dish out macro gymnastics in small doses at a time.The most complex macro I've done generated inline assembly statements from a standard string declaration. TI's C2000 series have 16bit chars so every string takes up double the size. For reasons unknown the statements to define "packed" strings are available only in assembly.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 29, 2017, 02:24:26 pm
content: Quote from: legacy on July 29, 2017, 01:06:00 pmMacros don't make mess. People make mess.People who don't like macros usually make more mess

author: legacy
author_rank: Super Contributor
timestamp: July 29, 2017, 03:40:05 pm
content: Quote from: NorthGuy on July 29, 2017, 02:24:26 pmPeople like the person with whom one works, especially in a profession or business?Sure, and it's a basket of plus all the time

author: MarkS
author_rank: Unknown
timestamp: July 29, 2017, 10:10:00 pm
content: Quote from: Back2Volts on July 29, 2017, 03:42:15 amUse macros to define constants. The macro processor is rather powerful and you can do a lot with it, but the more you do, the harder it gets to debug the code. If you need the macro to operate as a function, write a function.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 29, 2017, 11:45:31 pm
content: Quote from: MarkS on July 29, 2017, 10:10:00 pmPlease don't.You shouldn't use macros for anything that you can do in the language itself. It's much better to define numeric constants as enums. E.g.,Code:enum {FOO = 0x00000001u};is preferable to:Code:#define FOO 0x0000001u

author: hamster_nz
author_rank: Super Contributor
timestamp: July 30, 2017, 08:55:11 am
content: Quote from: andyturk on July 29, 2017, 11:45:31 pmEw! declaring things as unnamed, unused enums so you can use them as constants? That seems so dirty!At least it gets around the errors when you use a const to size an array:Code:$ cat c.cconst int sector_size = 512;unsigned char sector;int main(int argc, char *argv[]) {return 0;}$ gcc -o c c.cc.c:3:15: error: variably modified ‘sector’ at file scopeunsigned char sector;^But this works:Code:enum { sector_size = 512 };unsigned char sector;int main(int argc, char *argv[]) {return 0;}Me? I'ld take "#define SECTOR_SIZE (512)" any day.... but that you never know, it might grow on me.I might even make a macro for it!

author: NorthGuy
author_rank: Super Contributor
timestamp: July 30, 2017, 01:54:19 pm
content: Quote from: andyturk on July 29, 2017, 11:45:31 pmThe pre-processoristhe part of the C language.

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 02:10:48 pm
content: Quote from: NorthGuy on July 30, 2017, 01:54:19 pmWell, physically it's an external tool, since everything that begins with "#" (e.g. #define) is not handled by CC, it's pre-processed by CPP.C source & H header -> macro expansion (by CPP) -> object file (by CC).

author: NorthGuy
author_rank: Super Contributor
timestamp: July 30, 2017, 02:39:15 pm
content: Quote from: legacy on July 30, 2017, 02:10:48 pmThe C language is not concerned with the implementations. It is only concerned with the results:"The semantic descriptions in this International Standard describe the behavior of an abstract machine ..." C99 5.1.2.3.1

author: andyturk
author_rank: Frequent Contributor
timestamp: July 30, 2017, 03:36:09 pm
content: Quote from: hamster_nz on July 30, 2017, 08:55:11 amWell yeah, that works. One practical reason against macro constants is that they're unknown to your debugger, since they get stripped away before the compiler. Macros are also sloppy when it comes to strong typing.Frequently, I'll use enums in an API when I want to make sure that an argument to a function/method has a limited range of values and enforce that at compile time. ints are, well, integers, and force you to check stuff at runtime (if at all).Truth be told, I spend most of my time in C++ and depend heavily on compile-time type checking to keep me out of the weeds. Things like strongly type enums and 'const' (did I just hear a gasp from the back row?) flush a lot of problems out before I fire up the J-Link.And my static constexpr function can beat up your #define expansion any day of the week. ;-)Quote from: NorthGuy on July 30, 2017, 01:54:19 pmIs it really? The C standard is pretty specific about how expressions are evaluated. E.g., what something like "a+b" means when the types of the identifiers are specified. But when you don't know those types, the standard won't have much to say.I've got a special rule in most of my makefiles that produces the preprocessed output only (i.e., no object code) specifically for tracking down goofy things that happen with macros:Code:$(BUILD)/%.E : %.c | $(BUILD)@echo Compiling $(subst $(ABS_ROOT),,$(<))@$(CC) $(CFLAGS) -E -c $< -o $(@)I like the preprocessor for #include, #pragma once and X-macros, but constants and inline functions are better handled (IMO) by constants in the language itself and inline functions....I'll confess that I've been abusing the preprocessor on a recent project though. Some of the code is automatically generated (CubeMX) and the generated main() conflicts with mine, causing the linker to complain.But the preprocessor can get around this by changing function names from the outside. Another gnu makefile snippet:Code:$(OBJ)/$(BOARD)/cubemx/Src/main.o : CFLAGS += -Dmain=cubemx_generated_mainThat defines "main" to be a macro that evaluates to some other name, but just for the compilation of that one specific file. It requires a target-specific variable definition in the Makefile, which I'm sure crosses a line.But it's a lot easier than having to sed the output.

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 04:28:07 pm
content: Quote from: NorthGuy on July 30, 2017, 02:39:15 pmPrecisely another defect of the C language: are you really sure two implementations produce exactly the same results? In several circumstances I have experimented different behaviors with different compilers and pre-processors.But the point was: the macro processor simply replaces patterns without being aware of the size, type and signed.Too bad.

author: Nusa
author_rank: Super Contributor
timestamp: July 30, 2017, 05:19:52 pm
content: Quote from: legacy on July 30, 2017, 04:28:07 pmIndeed. Over the years I've lost count of the number of annoying portability errors I've fixed simply by moving same-line // comments to their own line. Mostly in other peoples code. I learned not to same-line comment defines a long time ago, even if you can get away with it 99% of the time.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 30, 2017, 06:00:32 pm
content: Quote from: legacy on July 30, 2017, 04:28:07 pmOf course, there could be bugs in implementations. It's true for every language or tool. How's that a defect of a language?From my experience, bugs are relatively rare in C. If you stick to the standard and understand what you're doing, it is very likely to be portable.Quote from: legacy on July 30, 2017, 04:28:07 pmThat's right. It writes your program for you exactly as you said. Why should it worry about the types? Like text editor. It doesn't worry about types. Does this bother you?

author: NorthGuy
author_rank: Super Contributor
timestamp: July 30, 2017, 06:12:05 pm
content: Quote from: andyturk on July 30, 2017, 03:36:09 pmThe C standard is also very specific about how the pre-processor work. In fact, it is more specific about the pre-processor than it is about typed expressions.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 30, 2017, 07:58:19 pm
content: Quote from: NorthGuy on July 30, 2017, 06:12:05 pmOK, so we can agree the preprocessor is both well defined and standardized. That doesn't mean it's a good idea to use macro substitutions for constants, although one certainly can.Let's flip it around... What advantages does a macro offer over a proper C constant?

author: MarkS
author_rank: Unknown
timestamp: July 30, 2017, 08:43:44 pm
content: Quote from: andyturk on July 30, 2017, 07:58:19 pmA macro defines a constant, i.e., the value doesn't change. To say this isn't a proper C constant is disingenuous.These are both functionally identical, at least to the compiler, although potentially producing slightly different (and irrelevant) machine code:Code:#define some_constant 100...int array;Code:enum{some_constant = 100};...int array;The difference is that one is evaluated during the preprocessor stage and one at compile time. Enums are more powerful yes, but that doesn't mean that the macros have no value. Ultimately, it comes down to familiarity. I started programming in C just shortly after enums came into the C vernacular, so #define is more familiar to me for this purpose. At the time all code examples used #define for constants; It's how I learned. One is different than the other, not one is good and the other bad. To be clear, most modern day compilers would produce exactly the same machine code from the above examples.Now, when you get into C++, the preprocessor is evil and to be avoided lest your computer go up in flames. In C++, you use "const".

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 09:00:50 pm
content: Quote from: MarkS on July 30, 2017, 08:43:44 pmit doesn't define anythingit replaces occurrences in the text.It does the same job as SED.

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 09:02:31 pm
content: Quote from: andyturk on July 30, 2017, 07:58:19 pmit's not.e.g. sierra cpp vs gnu cpp

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 09:24:44 pm
content: QuoteFalse. It's implementation dependent.e.g. if you put functions inside an expression, the order in which functions are evaluated is known that might be different depending on the used C compiler.The same happens with the macro processor for complex macros, typically when you try to define a function with a macro.The C language is affected by "nasal demons". Undefined behaviors where the semantics of certain operations is described as undefined on the executing computer code whose behavior is not prescribed by the language specification to which the code adheres. This happens when the translator of the source code makes certain assumptions, but these assumptions are not satisfied during execution.Since all the assumptions made by cpp come from a simple "text replacement", there is no information between these two modules, and, as consequence, nasal demons can take place without a single line of warning.“When the compiler encounters [a given undefined construct] it is legal for it to make demons fly out of your nose”Be warned about that.

author: MarkS
author_rank: Unknown
timestamp: July 30, 2017, 09:34:32 pm
content: Quote from: legacy on July 30, 2017, 09:00:50 pmDon't be pedantic.

author: MarkS
author_rank: Unknown
timestamp: July 30, 2017, 09:35:34 pm
content: Quote from: legacy on July 30, 2017, 09:02:31 pmWe're not talking about C++.

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 09:41:58 pm
content: Quote from: MarkS on July 30, 2017, 09:34:32 pmI assume you don't know what "define" implies!type? size? kind? ... they are not optional since they can cause problems.None of them are defined by #define. It's a good practice to force the size of a constant, but it's not a must. Thus people do what they want do to, and the source code is usually I mess.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 30, 2017, 09:45:57 pm
content: Quote from: andyturk on July 30, 2017, 07:58:19 pmPre-processor lets you do lots of different things. What you mean by "defining constants" is just a very small part of it. You can use macros as you see fit. It is nothing wrong with this. Same with "enum" - you can use it as you see fit and this is nothing wrong with this neither.The purpose of macros and enums are different. Sometimes there could be a situation where you can use a macro or enum. Well, use either. It doesn't matter. Your programs won't get better if you always use enums in these situations. Nor are they going to get better if you decide not to use enums. These choices have nothing to do with the quality of the software you write. But, if you concentrate on algorithms and other tangible things instead of worrying about choices between macros and enums, your software will get better.

author: legacy
author_rank: Super Contributor
timestamp: July 30, 2017, 10:00:42 pm
content: Quote from: MarkS on July 30, 2017, 09:35:34 pmSierraC is not C++I compared a C compiler with another C compiler.If you prefer you can see the difference between- intelC- Gcc/C- Watcom C- SierraC- ...Now don't want to make a point of distinguishing between- implementation-defined- unspecified- undefined behaviorprobably, in your head, they sound irrelevant like something that will never happen. Hope so, otherwise looking at several C compilers for business job to do, you might have some exciting news about your assumptions.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 30, 2017, 10:24:11 pm
content: Quote from: NorthGuy on July 30, 2017, 09:45:57 pmActually, understanding how to use the language well is part of what makes code "better". Using the preprocessor macros for constants was OK 40 years ago, when the compiler didn't support constants. But there's no real utility in doing that today, and lots of drawbacks.Googlebasically outlaws preprocessor macros for their 100M+ line C++ codebase.EDIT:Morefrom Google on macros.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 30, 2017, 11:05:58 pm
content: Quote from: andyturk on July 30, 2017, 10:24:11 pmOf course, you need to understand the language you use. But it is actually a very small and not important part of the programming process. If you come up with a good solution, you can write it in C, or in Pascal, or Whatever, and you will get very similar result. Even though C has macros (and I would probably use them in most cases), but Pascal doesn't (and I would get by without them).Some languages, such as C# or java involve performance penalties at the outset. IMHO, it is silly to use them because you could just do the same in C with approximately the same effort, and results would obviously be better. But many people seem to be delusional about that - they think that using certain languages instead of others give them some sort of magical advantage.Google. They certainly like imposing their rules on the world. Doesn't mean their rules are any good.

author: hamster_nz
author_rank: Super Contributor
timestamp: July 31, 2017, 12:08:03 am
content: Quote from: andyturk on July 30, 2017, 10:24:11 pmIf only the could outlaw paying their fair share of taxes as easily....One benefits of #define is that it provides a path to share information between the build environment and the resulting code - usually the -D command line switch.

author: John Coloccia
author_rank: Super Contributor
timestamp: July 31, 2017, 01:01:21 am
content: Google is talking C++ code, not C, and there are C++ ways to do things that don't require the use of a traditional macro.const int i = 5;int array;is just one example that works in C++ and doesn't work in C for normal arrays.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 31, 2017, 02:10:16 am
content: Quote from: hamster_nz on July 31, 2017, 12:08:03 amYup. Very handy.Quote from: John Coloccia on July 31, 2017, 01:01:21 amYou sure?Code:#include <stdio.h>const int i = 10;int array;int main(int argc, char *argv[]) {printf("sizeof(array) = %lu\n", sizeof(array));}When I compile this on a mac using the C89 standard, it works just fine:Code:$ cc -std=c89 foo.c$ ./a.outsizeof(array) = 40$ cc --versionApple LLVM version 8.1.0 (clang-802.0.42)Target: x86_64-apple-darwin16.7.0Thread model: posixInstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin$Heck, it even allows a const in in a case with -std=c89:Code:void foo(int arg) {switch (arg) {case i : break;default : break;}}So, if the C standard of 28 years ago allows for these kinds of constants, is there still a reason to be using #define for this stuff in 2017?

author: hamster_nz
author_rank: Super Contributor
timestamp: July 31, 2017, 02:31:36 am
content: Quote from: andyturk on July 31, 2017, 02:10:16 amNot on GCC 4.8.4:Code:$ gcc -o c c.c -std=c89c.c:4:5: error: variably modified ‘array’ at file scopeint array;^Didn't work with standards of c89, c99, c11, gnu99, gnu11...

author: NorthGuy
author_rank: Super Contributor
timestamp: July 31, 2017, 03:57:28 am
content: Quote from: andyturk on July 31, 2017, 02:10:16 amIt is illegal according to C99 standard. It may work in your compiler. But if you use it with other C compiler it may fail. Therefore, if you want portability, you shouldn't use it. If portability is not needed then it is Ok, of course.BTW, While your code is illegal, this would be perfectly legal in function scope:Code:[#include <stdint.h>#include <stdio.h>const int z = 5;int main(void){int x;int k = sizeof(x);printf("sizeof = %d\r\n",k);}But this actually creates a variable-size array instead of a constant one. What difference does it make? A very noticeable one. Here's the result (GCC 4.5.0 on Linux):Code:.globl main.typemain, @functionmain:leal4(%esp), %ecxandl$-16, %esppushl-4(%ecx)pushl%ebpmovl%esp, %ebppushl%ebxpushl%ecxsubl$16, %espmovl%esp, %eaxmovl%eax, %ebxmovlz, %eaxdecl%eaxmovl%eax, -12(%ebp)movlz, %eaxsall$2, %eaxaddl$15, %eaxaddl$15, %eaxshrl$4, %eaxsall$4, %eaxsubl%eax, %espmovl%esp, %eaxaddl$15, %eaxshrl$4, %eaxsall$4, %eaxmovl%eax, -16(%ebp)movlz, %eaxsall$2, %eaxmovl%eax, -20(%ebp)movl$.LC0, %eaxsubl$8, %esppushl-20(%ebp)pushl%eaxcallprintfaddl$16, %espmovl%ebx, %espleal-8(%ebp), %espaddl$0, %esppopl%ecxpopl%ebxpopl%ebpleal-4(%ecx), %espretNow, let's try the same with a macro:Code:#include <stdint.h>#include <stdio.h>#define z 5int main(void){int x;int k = sizeof(x);printf("sizeof = %d\r\n",k);}Here's the result:Code:.globl main.typemain, @functionmain:leal4(%esp), %ecxandl$-16, %esppushl-4(%ecx)pushl%ebpmovl%esp, %ebppushl%ecxsubl$36, %espmovl$20, -12(%ebp)movl$.LC0, %eaxsubl$8, %esppushl-12(%ebp)pushl%eaxcallprintfaddl$16, %espmovl-4(%ebp), %ecxleaveleal-4(%ecx), %espretJust to clarify, here's the extra bloat the "constant" version produces compared to the "macro" version of the code:Code:movl%esp, %eaxmovl%eax, %ebxmovlz, %eaxdecl%eaxmovl%eax, -12(%ebp)movlz, %eaxsall$2, %eaxaddl$15, %eaxaddl$15, %eaxshrl$4, %eaxsall$4, %eaxsubl%eax, %espmovl%esp, %eaxaddl$15, %eaxshrl$4, %eaxsall$4, %eaxmovl%eax, -16(%ebp)movlz, %eaxsall$2, %eaxmovl%eax, -20(%ebp)You didn't expect such a result, did you?

author: andyturk
author_rank: Frequent Contributor
timestamp: July 31, 2017, 04:45:30 am
content: Quote from: hamster_nz on July 31, 2017, 02:31:36 amHmm. Maybe Clang/LLVM is being too flexible here.Quote from: NorthGuy on July 31, 2017, 03:57:28 amYuck. Definitely don't want a variable-sized array.QuoteTo be honest, I was surprised the example compiled with -std=c89, but didn't investigate further. My mistake. Most of my work these days is with GCC 5.x and 6.x for Cortex-M, so what works (or doesn't) with other compilers and/or architectures isn't something I spend much time thinking about. I'm much more up-to-speed on the differences between std=c++11 and std=c++14 though.So it seems that if you're dealing with ancient compilers or ancient standards (e.g., C89), then yes, by all means keep using #define for constants. But the case for continuing that style with more modern compilers seems less clear.

author: hamster_nz
author_rank: Super Contributor
timestamp: July 31, 2017, 05:11:03 am
content: Quote from: NorthGuy on July 31, 2017, 03:57:28 amCool! So the stack is the new heapMentally I'm still stuck with a fixed size stack frame.How do you trap memory exhaustion with that one? Because you will be far more likely to blow the stack than if you are holding fixed length frames.And does that mean that all nested variable declarations in a function become computed rather than 'base_pointer+fixed_offset_in_stack_frame' addressing? For example:Code:int func(int a) {int array;/* do stuff with array */if(....) {int b;/* Do stuff with b, which will not be at a fixed offset in the stack frame but depends on the size of 'array' */}}Oh, and how does it handle alignment - does it round up the allocated size to ensure that things won't cross the native word boundaries?So many questions, so little sense of what the machine will actually be doing...But I can see how it prevent programmers from leaking memory by malloc()ing but not free()ing buffers.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 31, 2017, 03:29:21 pm
content: Quote from: andyturk on July 31, 2017, 04:45:30 amI see, magic new compilers and all that. We've heard it well before the ancient compilers which I use today ever appeared.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 31, 2017, 03:50:18 pm
content: Quote from: NorthGuy on July 31, 2017, 03:29:21 pmI'm curious, which "ancient compilers" are you using?

author: NorthGuy
author_rank: Super Contributor
timestamp: July 31, 2017, 03:53:24 pm
content: Quote from: hamster_nz on July 31, 2017, 05:11:03 amIf there's only one variable array, the compiler still can use 'base_pointer+fixed_offset_in_stack_frame'. It just has to allocate the array at the end of all other variables. Although it depends on the architecture - stack may grow up or down, there may be parameters in the stack etc.If there are very many of these, it gets very hard for the compiler. It has to allocate all these arrays and not to lose the track where they are. Since the stack pointer is moving during the allocation process, it's not that easy to find storage for all the corresponding. Probably the best idea is to maintain a linked list of allocated arrays in the stack, and then when everything is done you can walk through the list, extract the pointers and store them at fixed locations relative the stack frame base. Such a PITA to implement for the compiler, and then nobody uses it anywayI don't know how GCC does multiple arrays, but you can compile and look.But actually it is more efficient than the heap. This may be especially useful with small devices which do not have a heap. Also stack will not fragment. Of course, it makes it difficult to analyze stack behaviour. Not a problem on PC, but may be a problem with a small embedded.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 31, 2017, 04:19:43 pm
content: Quote from: andyturk on July 31, 2017, 03:50:18 pmYou wouldn't believe me if I told youThe assembly I posted was produced by:Code:[~]# gcc --versiongcc (GCC) 4.5.0Copyright (C) 2010 Free Software Foundation, Inc.This is free software; see the source for copying conditions. There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

author: John Coloccia
author_rank: Super Contributor
timestamp: July 31, 2017, 10:34:23 pm
content: BTW, thanks to everyone that picked up on my typo and knew what I was trying to say without making a big deal about it!FWIW, the coding standards I just finished writing says something to the effect of, "Avoid macros where possible...prefer to use const." I wish coding standards could simply say, "Please, just make your code look like the code around it, and otherwise just use common sense and don't make a mess," but that never seems to work.

author: andyturk
author_rank: Frequent Contributor
timestamp: July 31, 2017, 11:41:25 pm
content: Quote from: John Coloccia on July 31, 2017, 10:34:23 pmClang-format goes a long way towards eliminating time spent fussing over code formatting. The projects I work on use it as the de facto description of what code is supposed to look like. I.e., we discuss/argue over how to configure the formatter, and then the rule becomes: "Clang-format everything before you check it in. Period." It integrates with many stand-alone editors these days, and some folks even set it up as a pre commit hook.https://clang.llvm.org/docs/ClangFormat.htmlWhen someone hands me a bunch of ugly OEM code that wraps at the 200th column (or some such), I just clang-format the whole thing in emacs. Takes a couple of seconds.

author: NorthGuy
author_rank: Super Contributor
timestamp: August 01, 2017, 02:38:08 am
content: Quote from: John Coloccia on July 31, 2017, 10:34:23 pmPerhaps you hire wrong people.

author: Fredderic
author_rank: Regular Contributor
timestamp: August 01, 2017, 05:43:26 am
content: Quote from: NorthGuy on July 31, 2017, 03:53:24 pmActually, pretty sure the stack pointer is pretty much irrelevant during execution of a function. It's the base pointer that anchors the functions arguments and locals. The compiler simply allocates ALL variables a slot on the stack at compile time, regardless of where in the function they occur, at what scope depth, etc., which includes stack-allocated arrays — they get a pointer variable up-front like any other array. The compiler then basically does the equivalent of inlining a malloca call, to allocate the actual array. Since the base pointer anchors the function arguments and locals, the stack pointer can do what it likes, and you simply subtract as much space as you need off the stack pointer, and use that as the base of your array.Seriously, in the middle of a function, pick a small random number, subtract it from the stack pointer, and everything keeps working just fine. You can do it as often as you like (as long as you don't run out of stack space, of course), and all you've done is wasted some space on your stack.It works because the compiler does essentially the exact same thing itself to allocate a functions own local variables. The caller basically pushes whatever it needs to save, followed by the arguments to the function it's calling, that function then pushes the current base pointer, and sets it to the current stack pointer, before subtracting the space it wants to allocate for it's own local variables. Done. On the way back out, it can simply ditch the current stack pointer, setting it back to the base pointer, load the previous base pointer back off the stack, and return back to the caller, which simply adds the space taken by those arguments back onto the stack pointer (rather than fiddling around with popping them off again). No need to keep track of anything much, other than the functions own arguments and locals.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 01, 2017, 07:27:26 am
content: Quote from: Fredderic on August 01, 2017, 05:43:26 amOn modern processors it is now mostly a convention - on older ones the hardware had special instructions that maintained the base pointer for you.Hence the following option in GCC:Quote

author: John Coloccia
author_rank: Super Contributor
timestamp: August 01, 2017, 07:36:14 am
content: Quote from: NorthGuy on August 01, 2017, 02:38:08 amOh, it doesn't matter who you hire. I could hire 10 copies of me and I'd still need to have written standards to keep it all straight. There are too many correct ways of doing something, but only one of them is right...the one in the standard.

author: legacy
author_rank: Super Contributor
timestamp: August 01, 2017, 09:27:42 am
content: Quote from: hamster_nz on August 01, 2017, 07:27:26 amI am thinking about the RISC way to pass parameters to a function to be called: they can use registers instead of pushing thing on the stack.But! Since registers are limited, it only works if parameters are compliant to the model (which is based on statistics, e.g. if usually functions have no more than 4 parameters, then 4 registers are reserved), otherwise we are back to the traditional model. In this case, on MIPS, I see a lot of compilers want to save the stack pointer before pushing on the stack, and then they simple resume comping back the frame pointer into the stack pointersave sp into fpreserve space for the return ansers (if any)push parameterscall the functionsave fp into sp

author: NorthGuy
author_rank: Super Contributor
timestamp: August 01, 2017, 01:36:44 pm
content: Quote from: Fredderic on August 01, 2017, 05:43:26 amYes, that is an easy mechanism if the compiler maintains a frame pointer which is separate from the stack pointer. I guess even if the compiler doesn't use frame pointers, it can make an exception for the functions with variable-size arrays.