[GCC] can't make a calculation as part of variable setup - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:22:02 am
content: Code:const uint8_t ADC_resolution = 13;uint8_t speed_0 = 0; // Percentage of speeduint16_t speed_0_ADC = (speed_0 * (2^ADC_resolution / 100)); // Pre-calculated value of ADCuint8_t speed_1 = 50; // Percentage of speeduint16_t speed_1_ADC = (speed_1 * (2^ADC_resolution /100)); // Pre-calculated value of ADCuint8_t speed_2 = 99; // Percentage of speeduint16_t speed_2_ADC = (speed_2 * (2^ADC_resolution / 100)); // Pre-calculated value of ADCconst uint8_t good_button_press = 50;const uint8_t startup_state = 0;uint8_t button_counts;uint8_t button_state = startup_state;uint8_t fan_speed;uint8_t current_fan_speed_input;uint8_t analogue_fan_channel_timer;Any assignment that requires a calculation throws up an error: Error initializer element is not constant.Should I just carry out the calculation on a new line?

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 08:25:22 am
content: Quote from: Simon on August 10, 2018, 08:22:02 amNo, that won't work. You need to make sure the initialization expression only contains constants and no variables.Alternatively you can have a separate initialization method in your code that happens one time to do the initial setup.

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:28:45 am
content: It's the statements that setup the variables that cause the problem:uint16_t speed_1_ADC = (speed_1 * (2^ADC_resolution /100));uint8_t button_state = startup_state;I am assigning the values of constants to variable, what is the problem.

author: johnwa
author_rank: Frequent Contributor
timestamp: August 10, 2018, 08:30:33 am
content: I think you will find that the caret ('^') operator doesn't do what you think it does...

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:32:37 am
content: it's not an exponent ?is uint16_t suitable for a constant?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 08:33:15 am
content: C treats consts like variables, and doesn't always understand that they can never changeChange the consts to #defines e.g.const uint8_t ADC_resolution = 13;to#define ADC_resolution 13

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 08:37:41 am
content: Quote from: Simon on August 10, 2018, 08:28:45 amWell, for example, speed_1 is not a constant and yet you are trying to use it in an initialization expression. That is why the compiler is objecting. Same with speed_0 and speed_2.

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 08:38:54 am
content: Quote from: mikeselectricstuff on August 10, 2018, 08:33:15 amI don't agree with this. Constant is as constant does. Using #define won't solve the problem, and will make the code harder to debug and test later on.

author: johnwa
author_rank: Frequent Contributor
timestamp: August 10, 2018, 08:41:31 am
content: Quote from: Simon on August 10, 2018, 08:32:37 am'^' is bitwise exclusive OR. There is a pow() function in the standard library , which works on doubles, but if you just want an integer power of 2, the left shift operator '<<' works well (at least, for unsigned quantities.) For 2^4, say, use '1 << 4'.

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:42:22 am
content: Quote from: IanB on August 10, 2018, 08:37:41 ameven if i make it a constant i get the same.

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:43:49 am
content: Quote from: mikeselectricstuff on August 10, 2018, 08:33:15 ami originally did that and it compiled ok but am told that it's not good practice and i can see that it can mask problems. Every time I try to follow best practice I land in more trouble.

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 08:44:47 am
content: Quote from: johnwa on August 10, 2018, 08:30:33 amQuote from: Simon on August 10, 2018, 08:32:37 amNo...For powers you need to use the pow() function.(Or what johnwa said)

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 08:49:53 am
content: Quote from: Simon on August 10, 2018, 08:42:22 amIf you replace this:Code:uint16_t speed_0_ADC = (speed_0 * (2^ADC_resolution / 100));with this:Code:uint16_t speed_0_ADC = (0 * (2^ADC_resolution / 100));It still doesn't compile?

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:52:15 am
content: Quote from: IanB on August 10, 2018, 08:49:53 amThan does, so it is complaining that a constant is not a constant!Code:const uint8_t speed_0 = 0; // Percentage of speeduint16_t speed_0_ADC = (speed_0 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADC

author: brucehoult
author_rank: Super Contributor
timestamp: August 10, 2018, 08:57:19 am
content: This is fine with g++:Code:#include <inttypes.h>const uint8_t ADC_resolution = 13;const uint8_t speed_0 = 0; // Percentage of speedconst uint16_t speed_0_ADC = (speed_0 * ((1<<ADC_resolution) / 100)); // Pre-calculated value of ADCconst uint8_t speed_1 = 50; // Percentage of speedconst uint16_t speed_1_ADC = (speed_1 * ((1<<ADC_resolution) /100)); // Pre-calculated value of ADCconst uint8_t speed_2 = 99; // Percentage of speedconst uint16_t speed_2_ADC = (speed_2 * ((1<<ADC_resolution) / 100)); // Pre-calculated value of ADCconst uint8_t good_button_press = 50;const uint8_t startup_state = 0;uint8_t button_counts;uint8_t button_state = startup_state;uint8_t fan_speed;uint8_t current_fan_speed_input;uint8_t analogue_fan_channel_timer;

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 08:59:02 am
content: right:project_variables.hCode:extern const uint8_t ADC_resolution;extern const uint8_t startup_state;extern const uint8_t speed_0; // Percentage of speedextern const uint16_t speed_0_ADC; // Pre-calculated value of ADCextern const uint8_t speed_1; // Percentage of speedextern const uint16_t speed_1_ADC; // Pre-calculated value of ADCextern const uint8_t speed_2; // Percentage of speedextern const uint16_t speed_2_ADC; // Pre-calculated value of ADCproject_variables.cCode:const uint8_t ADC_resolution = 13;const uint8_t speed_0 = 0; // Percentage of speedconst uint16_t speed_0_ADC = (speed_0 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADCconst uint8_t speed_1 = 50; // Percentage of speedconst uint16_t speed_1_ADC = (speed_1 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADCconst uint8_t speed_2 = 99; // Percentage of speedconst uint16_t speed_2_ADC = (speed_2 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADCconst uint8_t startup_state = 0;uint8_t button_state = startup_state;won't compile.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 09:03:42 am
content: Quote from: Simon on August 10, 2018, 08:43:49 amWhenever I hear people saying things are "best practice" it usually turns out they don't understand the problem or haven't given it any thought.There is almost never a "best" way to do something, only more or less applicable to a particular situation.Some older compilers would actually copy const variables to RAM at startup, so using const rather than #define would be actively bad compared to using #define.What problem exactly would it mask ?

author: hans
author_rank: Super Contributor
timestamp: August 10, 2018, 09:04:23 am
content: A classical discrepency between the GCC and G++ compilers. With godbolt.org, I noticed that this code (@brucehoult) will compile in GCC8.x and up, but not on older versions. On the other hand, it works in even the oldest G++ compilers.However.. before GCC8.x flows downstream to IDE packages, you probably have to wait half a dozen years.And I wouldn't recommended switching over a whole project to G++ because of this. That compiler is a bit stricter and your project may not compile (properly - under optimizations) elsewhere.I would recommended replacing the "constants" with a macro in this case.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 09:07:37 am
content: And with constants you also have to dick about with externs (or put them in a header file).You probably want constants like this in a header file anyway so all compile-time opitons are in the same place and not scattered throughout the codeFor this situation. #define works just fine, if not better.Just do it and get on with the job instead of worrying about what language purists think is good or bad practice.

author: janoc
author_rank: Super Contributor
timestamp: August 10, 2018, 09:11:38 am
content: Simon, that will not work. The language specification says the following aboutconst:QuoteWhatconstin C means is that you cannot modify that variable after it has been initialized (when used as an l-value). Whenconstvariable appears on theright side(r-value) of the assignment, theconstis effectively ignored. That's why you cannot do what you are trying to do.See here:https://en.cppreference.com/w/c/language/constBTW, calculating that value 2**ADC_resolution like that repeatedly is a bit silly - that value is a constant, why don't you precalculate that?

author: hans
author_rank: Super Contributor
timestamp: August 10, 2018, 09:13:33 am
content: Well , in another thread we ranted a lot about the pitfalls of macro's.. I don't like them, but in a GCC environment like this there is not better alternative.Still points up for writing down formulas in code, rather than the calculated values. It's more flexible, and the formula itself is already documentation rather than some "magic" number.You could write the formula in a function, but then you're not creating a const setup value. A compiler can optimize this away, though. But using a macro will probably yield the most deterministic code in terms of performance, as it needs to be fully evaluated irrelevant of optimization levels.If you only use this value at 1 location in your program (e.g. at initialization of peripherals), you could also do the calculation inside that function. Arguably a bit nicer than littering the program with more global variables.

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 09:16:44 am
content: I am trying to initialise it but i can't even do that. I declare the const name and then it won't take the value assingned. If i make the calculated value a variable instead the error is the same.

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 09:18:47 am
content: Quote from: hans on August 10, 2018, 09:13:33 amThe code is designed so that I can use any ADC resolution I like. By changing the one number all constants will adjust as will the oversampling algorithm and anything else.

author: janoc
author_rank: Super Contributor
timestamp: August 10, 2018, 09:20:44 am
content: Also, re #define vs const:Using #define (preprocessor macro) for constants is a bad practice because the compiler has no way to check the type of the value. #define is basically string replacement/concatenation before even the compiler sees it. So if someone #defines the constant to something unexpected or invalid, you are going to have a much harder time trying to find the problem - typical problem when changing between compilers. Relying on certain compiler behaviour (e.g. GCC) is a way to hell - when you will have to change to a non-GCC compiler for whatever reason (Visual C+++, clang, Microchip's PIC compilers, etc.) you will suffer.In C using #define macros for constants is the idiomatic solution because of exactly the problem you are facing (const doesn't declare a "constant" only that the given block of memory cannot be changed after initialization). Newer revisions of C++ useconstexprdeclaration to explicitly tell the compiler that something is constant at compile time - with that your code would work just fine. C doesn't have that, unfortunately.

author: janoc
author_rank: Super Contributor
timestamp: August 10, 2018, 09:24:17 am
content: Quote from: Simon on August 10, 2018, 09:18:47 amThen calculate that value once (it is the same value for all instances where you use it) and use the calculated value multiple times. Doing this at runtime, especially on a microcontroller, is a pretty expensive operation for no reason.But anyway, you can't write the code the way you want - you need to either switch to C++ and use constexpr (assuming your toolchain is modern enough to handle it) or you will have to precalculate these values/use macros because C doesn't allow non-constant expressions in the initializers (const foois not a constant expression!)

author: hamster_nz
author_rank: Super Contributor
timestamp: August 10, 2018, 09:28:44 am
content: This code actually compiles if you use the C++ compiler ('g++') rather than GCCCode:#include <stdio.h>const int i = 8;const int j = 10*i;int main(int argc, char *argv[]) {printf("i = %i, j = %i\n",i,j);}GCC gives:Code:a.c:3:22: error: initializer element is not constantSo why does 'C' not work? The way I think about it is....If the compiler is expected to retrieve values from the program's memory to retrieve a value to initialise a static variable, it won't compile.It fails because the initialization of 'j' requires the compiler to read the memory that will be allocated to hold i.So why is this the case?Imagine you had two code modules. The first one was justCode:/* define_i.c Define storage and set values for i */const int i = 8;And to go along with that you had a header file, to tell other modules all about 'i', but not what it's value actually isCode:/* define_i.h Header file */extern const int i;You might have legitimate reasons for doing this - you might define all your configuration variables in a file called "config.c", and have a "config.h" that allows other C programs to access the config settings.So now the main module could be:Code:/* main.c */#include <stdio.h>#include "define_i.h"const int j = 10*i;int main(int argc, char *argv[]) {printf("i = %i, j = %i\n",i,j);}When the compiler attempts to processes the "main.c" program into an object file, it knows that there is going to be a constant variable called 'i' somewhere in memory ( thanks to the declaration in "define_i.h"), however the value it has is not known to the compiler at that time.It is only when you have compiled both C programs and link them together that the value for 'i' gets defined.So why does it work for C++?C++ has the concept of constructors that (among other things) are used to initialise static variables. These are called before your main() function is run to handle cases like this. It is most likely also the source of undefined/random behaviors, as there is no clear order in which these get called, so most likely best avoided.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 09:30:46 am
content: Quote from: janoc on August 10, 2018, 09:20:44 amFor numerics like this I don't see a problem, maybe even avoids some unnecessary type conversions.possibly even some run-time calculations if the compiler isn't smart enough to flatten them into a compile-time constant.QuoteAny method is going to have problems with typos etc.Errors caused by #defines can sometimes be harder to find, though in the case of XC32 which is what I mostly use, it generally tells you where something was defined so typos etc. can usually be found easily.I'd argue that for something that is fixed at compile time like this, #define makes more sense than const, as const is semntically treated as a variable, which the compiler may or may not be smart enough to deal with efficiently.Just wondering if all compilers be smart enough to combine multiple floating point consts into an integer result without invoking any FP code?e.g.#define clock 24000000#define divclock clock*0.25

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 09:32:49 am
content: Quote from: janoc on August 10, 2018, 09:24:17 amYes in theory I can do the calculation once, in reality the time it takes at startup/compile is not an issue, one problem at a time.So in simple language how do I define a constant that is based on another?

author: brucehoult
author_rank: Super Contributor
timestamp: August 10, 2018, 09:34:52 am
content: By the way, this works fine in C. #define isn't the only answer.Code:#include <inttypes.h>enum {ADC_resolution = 13,ADC_factor = (1<<ADC_resolution) / 100,speed_0 = 0, // Percentage of speedspeed_0_ADC = speed_0 * ADC_factor, // Pre-calculated value of ADCspeed_1 = 50, // Percentage of speedspeed_1_ADC = speed_1 * ADC_factor, // Pre-calculated value of ADCspeed_2 = 99, // Percentage of speedspeed_2_ADC = speed_2 * ADC_factor, // Pre-calculated value of ADCgood_button_press = 50,startup_state = 0,};uint8_t button_counts;uint8_t button_state = startup_state;uint8_t fan_speed;uint8_t current_fan_speed_input;uint8_t analogue_fan_channel_timer;#include <stdio.h>int main(){printf("speed_0_ADC = %d\n", speed_0_ADC);printf("speed_1_ADC = %d\n", speed_1_ADC);printf("speed_2_ADC = %d\n", speed_2_ADC);return 0;}

author: Kalvin
author_rank: Super Contributor
timestamp: August 10, 2018, 09:35:51 am
content: Another solution is to call a specific initialization function in main() only once right after device power-up, which would precompute the "constant" values at runtime. A more standard solution is to go with the #define way. One extreme solution is to use an external program/script generating a C header file with precomputed constant values and include this header file into the project.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 10, 2018, 09:36:09 am
content: Quote from: Simon on August 10, 2018, 09:32:49 amCode:#define BITS (10)const int max_val = (1<<BITS)-1;

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 09:37:04 am
content: So if I make all of these variables does it solve the problem? RAM is not an issue.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 10, 2018, 09:43:06 am
content: Quote from: brucehoult on August 10, 2018, 09:34:52 amThat is nice, in an ugly way, define the values in enums, then store the enums in variables... does it work for floats or doubles?

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 09:47:42 am
content: Quote from: Simon on August 10, 2018, 09:37:04 amWell, sure. It's the difference between initialization and assignment.For example, while this won't work:Code:int n = 3;int m = 5 * n;This will work:Code:int n, m;n = 3;m = 5 * n;

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 09:51:02 am
content: sounds like constants in C are still bollocks and the only true constant is a define.So I need to split the operations up.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 10, 2018, 09:51:43 am
content: Quote from: IanB on August 10, 2018, 09:47:42 amNot for me:Code:$ cat main.c#include <stdio.h>int i;int j;i = 5;j = i*10;int main(int argc, char *argv[]) {printf("i = %i, j = %i\n",i,j);}Code:$ gcc -o main main.cmain.c:4:1: warning: data definition has no type or storage classi = 5;^main.c:4:1: warning: type defaults to ‘int’ in declaration of ‘i’ [-Wimplicit-int]main.c:5:1: warning: data definition has no type or storage classj = i*10;^main.c:5:1: warning: type defaults to ‘int’ in declaration of ‘j’ [-Wimplicit-int]main.c:5:5: error: initializer element is not constantj = i*10;^

author: brucehoult
author_rank: Super Contributor
timestamp: August 10, 2018, 09:53:43 am
content: Quote from: hamster_nz on August 10, 2018, 09:43:06 amNo floating point. Only char, short, int, long, long long and the corresponding unsigned variants.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 09:53:50 am
content: Quote from: IanB on August 10, 2018, 09:47:42 ambut would be a PITA as it would need to be declared extern in any module that needs it.I've yet to see a convincing argument (for this situation) against #defining it all in a header file included by all modules. Just remember to bracket any expressions to avoid operator precedence issuesAlso simplifies product variants where different sets of constants are used.

author: hans
author_rank: Super Contributor
timestamp: August 10, 2018, 09:56:33 am
content: Quote from: brucehoult on August 10, 2018, 09:34:52 amI think I've seen the EFM32 libraries being built in this way, although at most they were doing was some bit banging for registers.But I wasn't a real fan of that style. Sure it works and the compiler does it's job, but it can be confusing.Nonetheless, sounds like there is a lot of debate how to put in constants in a program. Nice to see all the solutions.I think generally speaking for C with the given tool limitations, most people hardcode numbers into a program or resort to a macro.Sure you can do better in C++, but speaking as embedded in a single entity, weare not ready for that yet.Quote from: mikeselectricstuff on August 10, 2018, 09:30:46 amG++ 4.1.2: thinks the outcome is a double (rightly so) and complains when trying to squeeze it into an integer somewhere.G++ 4.4.7 already does animplicitconversion back to integers..GCC 4.1.2: does same as G++ 4.4.7Not sure what other compilers might do, like CCS, IAR or XC8.

author: IanB
author_rank: Super Contributor
timestamp: August 10, 2018, 10:01:44 am
content: Quote from: hamster_nz on August 10, 2018, 09:51:43 amWell, true. But of course you didn't put the executable statements in a function block. Some details are left for the reader.

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 10:14:21 am
content: OK I am back to defines, but#define speed_0_ADC ((speed_0 * (((1 << ADC_resolution) - 1) / 100))U) does not work, do I need to care about the "U" as it is always a positive value?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 10:17:26 am
content: Quote from: Simon on August 10, 2018, 10:14:21 amIf you're using #define, you don't include the type, so no "U"

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 10:19:06 am
content: #define ADC_1_percent (((1 << ADC_resolution) - 1) / 100) // raw oversampled ADC value of 1%#define speed_0 0U // Percentage of speed#define speed_0_ADC (speed_0 * ADC_1_percent) // Pre-calculated value of ADC#define speed_1 50U // Percentage of speed#define speed_1_ADC (speed_1 * ADC_1_percent) // Pre-calculated value of ADC#define speed_2 99U // Percentage of speed#define speed_2_ADC (speed_2 * ADC_1_percent) // Pre-calculated value of ADC

author: Simon
author_rank: Unknown
timestamp: August 10, 2018, 10:20:36 am
content: Quote from: mikeselectricstuff on August 10, 2018, 10:17:26 amBut we always have to do: #define F_CPU 8000000ULdiscreet values with "U" on the end work, the issue is putting it after the formula

author: brucehoult
author_rank: Super Contributor
timestamp: August 10, 2018, 10:25:28 am
content: Quote from: Simon on August 10, 2018, 10:14:21 am*What* is that U doing there?You can add a "U" as part of the syntax of an integer: 123U. Just like a "." is part of the syntax of a floating point number."U" isn't something you can just throw in at random as some kind of type conversion operation.There's #define speed_0_ADC ((unsigned)(speed_0 * (((1 << ADC_resolution) - 1) / 100)) for that.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 10, 2018, 10:30:23 am
content: Quote from: Simon on August 10, 2018, 10:14:21 amIt really isn't needed in this case, but if it was important, you want to use a 'type cast':Code:#define ADC_RESOLUTION (12)#define ADC_MAX ((1 << ADC_RESOLUTION) - 1)#define ADC_SPEED_PERCENT(x) ((uint_32)( x * ADC_MAX / 100))const uint_32 speed_0_ADC = ADC_SPEED_PERCENT(0)const uint_32 speed_1_ADC = ADC_SPEED_PERCENT(50)const uint_32 speed_2_ADC = ADC_SPEED_PERCENT(99)You also will want to be careful/mindful about overflows too.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 10, 2018, 10:45:28 am
content: Quote from: Simon on August 10, 2018, 10:20:36 amwhy? surely if a value is big enough to need a long, the compiler will figure that out in the context where the constant gets used.Only numeric values can have the type suffixes, so if you need them, only put them after things that are numbers.so :#define speed_0 1000UL#deifine ADC_resolution 13UL#define speed_0_ADC ((speed_0 * (((1 << ADC_resolution) - 1) / 100UL)))

author: hamster_nz
author_rank: Super Contributor
timestamp: August 10, 2018, 10:50:43 am
content: Quote from: mikeselectricstuff on August 10, 2018, 10:45:28 amThose damn 16-bit C compilers used on small micros...

author: janoc
author_rank: Super Contributor
timestamp: August 10, 2018, 12:03:15 pm
content: Quote from: mikeselectricstuff on August 10, 2018, 09:30:46 amNever had a problem with differently sized types on different compilers? Or signed vs unsigned? All of that gets muddied up if you use macros - the compiler will promote the literal to whatever type it needs to perform the operation - which may not be the type the programmer has intended (or assumed). If you use a const instead, the type is explicit and if the conversion would be problematic you at least get a warning about it.Quote from: mikeselectricstuff on August 10, 2018, 09:30:46 amI wasn't referring so much to typos (those tend to be obvious) but things such as libraries (re)defining various things behind your back. Typical cases are the min/max macros, size_t, char being redefined as unsigned char, etc. That can break code in subtle ways you won't notice because the code will likely still compile. Just not behave as expected.Quote from: mikeselectricstuff on August 10, 2018, 09:30:46 amThat applies only for C where the compiler (or rather the language standard) is sadly too dumb and prevents many of these compile-time optimizations.Quote from: mikeselectricstuff on August 10, 2018, 09:30:46 amIf you define it like this - i.e. macros, then not. The use of divclock gets literally substituted for clock * 0.25 which is of double type. Not to mention that you should put the macro in parentheses, i.e. (clock * 0.25) otherwise you may get an unexpected surprise if it gets used in an expression with a higher priority operator than a multiplication next to it. The preprocessor works really on the text search & replace level, nothing more. I think the xc32 compiler is GCC-based, so you can see the preprocessing result by running it with the -E switch on your source file. It will stop after the preprocessing stage before compilation and you can see the results of the macro substitutions. You will see that the preprocessor does not do any arithmetics there for you.OTOH, if you use C++11 or newer, you can do this:constexpr int clock = 24000000;constexpr int divclock = clock / 4;and this will be calculated by the compiler at compile time and optimized out, basically ending as equivalent to writing:constexpr int divclock = 6000000;If you are wondering why did I replace the multiplication by 0.25 by division by 4 - multiplication by 0.25 will work too but it will end up promoted to double and then truncated into the int constant expression. That will likely trigger a warning about a possible data loss due to the truncation. Division by 4 is an integral division in this case, so no warning. Another way of avoiding that warning would be by using an explicit cast there.

author: janoc
author_rank: Super Contributor
timestamp: August 10, 2018, 12:13:38 pm
content: Quote from: hamster_nz on August 10, 2018, 10:50:43 amMore like 8 bit compilers - that macro is from 8bit AVRs. The compiler itself doesn't need it but a lot of standard AVR library code relies on this macro being defined with the MCUs clock frequency because many functions need to calculate various delays and dividers.

author: snarkysparky
author_rank: Frequent Contributor
timestamp: August 10, 2018, 12:52:26 pm
content: for the compiler not knowing the type of a #define can you do this#define someconst (unsigned)42

author: legacy
author_rank: Super Contributor
timestamp: August 10, 2018, 01:11:42 pm
content: don't abuse #define

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 10, 2018, 01:27:27 pm
content: i have a hunting knife and it has this sawtooth like on the top that always bite me in the ass, that knife is not good and its not the safe practice, kitchen knife will be better because it has no sawtooth on the top, safe. knife is at fault not me, i'm perfect and clever, dont use define because i'm too lazy to declare type safe code and i can produce whatever bug in the program, define is at fault, define creates bugs not me. i'm perfect and better than Bjarne Stroustrup, i may as well design my own language and compiler, this is neverending story, people already went to the moon, we are here debating while polishing our fat ass, because thats good.

author: legacy
author_rank: Super Contributor
timestamp: August 10, 2018, 03:03:51 pm
content: Quote from: Mechatrommer on August 10, 2018, 01:27:27 pm

author: andyturk
author_rank: Frequent Contributor
timestamp: August 10, 2018, 03:13:09 pm
content: Off-topic opinions on C++ follow...Quote from: hamster_nz on August 10, 2018, 09:28:44 amStatic constructors are always called in order for a given file. But you're right, it's difficult to predict the initialization order of static variables that appear in different files. The problem isn't constructors though... Constructors are very useful! The issue is with using static class instances. The fewer static instances you have, the better.You can (almost) have your cake and eat it too withplacement new. You can allocate memory statically for an instance of a class, but delay calling the constructor until somewhere within main(). I use a template for that:Code:/*** @brief returns a reference to a singleton instance* @tparam T the type of the singleton** This template function uses placement new to statically allocate* memory for a single class instance, but delay its construction* until the function is called for the first time.** Subsequent calls to the<T> return the same instance. The* constructor for T will only be called once.*/template <class T>T &the() {alignas(T) static char memory[sizeof(T)];static T * instance = nullptr;if (instance == nullptr) instance = new (memory) T;return *instance;}and my main() usually looks like this:Code:int main() {the<Application>().run();return 0;}

author: snarkysparky
author_rank: Frequent Contributor
timestamp: August 10, 2018, 03:24:55 pm
content: Well might the gods of "best practice" actually shine their light on the situation, just this once, and bestow their wisdom upon the mere mortals of the planet.

author: brucehoult
author_rank: Super Contributor
timestamp: August 10, 2018, 10:20:37 pm
content: Quote from: snarkysparky on August 10, 2018, 03:24:55 pmIt seems pretty simple to me. "Best practice" is to read and understand the manual for the tool you've chosen to use, and then decide for yourself how you want to use its capabilities and features.Flailing around entering random input into your tool and expecting it to somehow intuit what you want is not best practice.C is one of the simplest, most transparent, and least magical programming tools there is, second only to actual assembly language and maybe such simple orthogonal languages as FORTH or Scheme. The manual tells you precisely what you can do, what you can't do, and what is undefined.With all of those simple languages you can build anything you want -- you're not restricted to what Brendan Eich or Guido van Rossum decided you should be able to do. The downside is that you *have* to build everything you want.

author: westfw
author_rank: Super Contributor
timestamp: August 10, 2018, 10:40:10 pm
content: QuoteQuoteQuoteThese are pretty extreme "solutions" for conforming to a "#defines are bad practice" suggestion, for a case where I think #define would work just fine. (Especially the "enum" one - "#define is untyped, so instead we're going to use enum, which is a poorly defined type not-very-much like the actual data")QuoteI wish they had never ported C to that damned PDP11!(actually, you don't need the "L" on numbers like 1000000; you're more likely to need "1L")

author: ejeffrey
author_rank: Super Contributor
timestamp: August 11, 2018, 03:26:18 am
content: Quote from: hans on August 10, 2018, 09:04:23 amWell it isn't much a discrepancy between gcc and g++ as between C and C++.C requires that all global variable initializers be expressions of literals. A variable, even a "const" variable is not allowed in the initializer expression. In principle, the language could be changed to allow "const" varaibles whose value is known, but this is not the case. Note: you can have a "const" variable whose value is not known at compile time. For instance, it could be "extern" (defined in a different source file), volatile (changeable by an external event), or forward declared with the value occurring later in the file.This is one reason (of many) that despite the problems with #define macros it is most common to use #define for compile time constants, especially when you need multiple constants derived from each other.C++ on the other hand lets you initialize global variables with almost anything you want including runtime computation. This is handled by linker magic. For instance, on ELF systems, every object file has a ".init" section. Initializer code is placed in there and the linker makes sure that all code in .init sections gets called before main().Note that this has "interesting" behavior too. The order of initializers in different translation units is undefined, so initializing a variable from an "extern" variable is pretty much always wrong. Furthermore, within a translation unit, the order of initialization depends on whether variables are const or not, *and* whether their initializer is a compile time constant.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 11, 2018, 06:15:41 am
content: Quote from: westfw on August 10, 2018, 10:40:10 pmAnother "solution" would be to quit worrying about having to compute everything at compile time. Composing a few bitmasks as the program runs isn't a big deal, and if it makes the code more readable/understandable, that's even better.Besides, compilers are *really* smart these days, and even code that looks bulky may get collapsed into constants by a good optimizer.

author: Nusa
author_rank: Super Contributor
timestamp: August 11, 2018, 06:29:06 am
content: Always remember that #defines are not constants, they're macro strings, and when you use them you're doingstring replacement. Any evaluation happens at their point of use.For example, some perfectly legal code:Code:#define A (2+#define B 2+3)#define C * 10// Type your code here, or load an example.int test() {return A B C;/* return (2+ 2+3) * 10; // looks like this after macro replacement *//* return 70; // looks like this after compiler optimization */}

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 11, 2018, 08:27:54 am
content: why people insist on using archaic cryptic U or L?that is meant for backward compatibility for languages that dont support more civilized syntax? when C already provides clearer and much more configurable type safe syntax such as:Code:#define my_data uint_32#define my_const ((my_data)(3141))otoh const <insert whatever data type> myVar will stay in memory forever and people or me and you can change the value with whatever untype unsafe syntax provided by the language. its best to think how compiler will do its job at compile time imho.Quote from: Nusa on August 11, 2018, 06:29:06 amits the people who code in such a way that embarked those people who complained C/C++ is cryptic garbage mess and not safe practice... i did it once (long time ago) because i need massive typing shortcut and save me alot of trouble when i tried to improve the code chunk which occured very many times, but this technique better we keep to ourself rather than advising people to do the same. its a "nasty language hack" that we can do with C/C++

author: Nusa
author_rank: Super Contributor
timestamp: August 11, 2018, 10:12:36 am
content: I wasn't trying to demonstrate good practice, I was trying to emphasize the nature of #defines. Thinking of them as constants means you're going to burn yourself again and again when you forget about operator precedence or forget necessary parentheses.#define A 2+2#define B (2+2)int i = A;int j = B;int k = A * 10;int l = B * 10;// the values of i,j,k,l are 4,4,22,40. Do you understand why?

author: legacy
author_rank: Super Contributor
timestamp: August 11, 2018, 11:24:50 am
content: Quote from: IanB on August 10, 2018, 08:38:54 amyup, and it makes the code harder to debug!

author: IanB
author_rank: Super Contributor
timestamp: August 11, 2018, 11:29:46 am
content: Quote from: legacy on August 11, 2018, 11:24:50 amBut I have learned that the C and the C++ standards are a little different in this regard, and it is important to know whether you are using C or C++ when considering what behavior to expect.(It is IMHO a little strange that the C and C++ languages are diverging. It would seem more sensible on the face of it for C to be a subset of C++.)

author: legacy
author_rank: Super Contributor
timestamp: August 11, 2018, 12:25:12 pm
content: I can't use C++ for my stuff, for a lot of reasons.Quote from: IanB on August 11, 2018, 11:29:46 amThe C language is defective in a lot of features, hence it's not weird that you see the C and C++ languages to diverge

author: mikerj
author_rank: Super Contributor
timestamp: August 11, 2018, 12:37:30 pm
content: Quote from: Simon on August 10, 2018, 09:51:02 amSounds like you simply don't have a very good grasp of C yet. If you define a 'const' value (const int my_const=5;), that value will exist in a memory location after the compiler has place it in the relevant memory section and the linker has allocated it an address. Any code with visibility of this const value can read it, either via immediate addressing or via a pointer. Since the preprocessor runs before the compiler (hence the name) you have been asking the preprocessor to use this value before it actually exists.When you use #define with a literal value (e.g. #define MY_VALUE 5) the preprocessor creates a symbol that it can subsequently use to to replace any later instances of the symbol with that literal value. This is not a constant value (though it can't change), it's aliteral. It won't have a unique memory address allocated for it, you can't access it via a pointer etc.

author: legacy
author_rank: Super Contributor
timestamp: August 11, 2018, 01:30:36 pm
content: hence it's bad for debugging.

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2018, 01:54:56 pm
content: Quote from: legacy on August 11, 2018, 12:25:12 pmWhat reasons?If you can use C++ on an Arduino Uno with 2 KB of RAM (as you do) then there aren't many places you can't use it.Using the C++ compiler doesn't force you to use any language features you don't want. You don't have to use exceptions. You don't have to use new and delete. You don't even have to use templates (though used skilfully they don't cause bloat) or classes (ditto). You can just treat C++ as a "better C".

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 11, 2018, 02:19:30 pm
content: thats why they said... go hunting or camping with kitchen knife thats much safer. otoh looking from my eye, there is a serious semantics ambiguity going on between constant the number and constant the variable (memory allocated), or constant as in mathematics, and constant as in computing science. as for me, i prefer anything that is allocated in memory as "not constant" and anything "defined" or literal as "constant". imo, "const" keyword in C/C++ is just to let the compiler know that a programmer cant change it in legitimate way. but once you cast it to void and then back to another non const pointer, then it will be changeable like flint. btw i guess some people will rely on memory monitor/view while debugging instead of common sense or mental strength of whats that define means and how its semantically translated into a program.

author: legacy
author_rank: Super Contributor
timestamp: August 11, 2018, 02:30:24 pm
content: Quote from: brucehoult on August 11, 2018, 01:54:56 pmNot technically reasons against C++, it's more a matter of convenience, i.e. I don't have enough money to buy a C++ compiler from Cosmic, while for my professional job, I am not often allowed to use C++ in avionics. We use Ada for everything needs abstraction and high-level design. Licenses for tools like Stood/C++ and Understand C++, as well as licenses for C++ debuggers, are usually 300-500% overpriced, hence as a freelancer, it's not so convenient for me to buy them, and I only have a regular pair of licenses for C's stuff. Anyway, in the past we did something in C++ (the customer paid for licenses, as their property), e.g. a couple of firmware for Avionics Full-Duplex Switched Ethernet (aka AFDX), but the testing and the qualifying of C++ code is usually a bloodbath

author: snarkysparky
author_rank: Frequent Contributor
timestamp: August 11, 2018, 04:20:41 pm
content: I see now. 5 expert in best practices would never even succeed in writing a hello world program if they must have consensus.99.999% of the software the world runs on has some suboptimal practice in the source.Experts in best practice will argue about a knats @zz until the sun burns out.Is it the norm in industry to have some smug sob criticize your code no matter what you do.I suspect when they craft code the concept of "good enough" runs in their head. But when debating or reviewing others code the criticism comes out.I'm frustrated by these discussions which contain megabytes of criticism but microbytes of suggestions.

author: legacy
author_rank: Super Contributor
timestamp: August 11, 2018, 04:47:20 pm
content: Quote from: snarkysparky on August 11, 2018, 04:20:41 pmhence, why don't you try to pass examinations like ACM and SIGACT in computer science (university), and then find a job in avionics, where you will be forced to master such concepts by practical contexts?

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 11, 2018, 06:44:34 pm
content: not applicable in eevblog junkyard... and certainly dont ask Simon to do so...

author: snarkysparky
author_rank: Frequent Contributor
timestamp: August 11, 2018, 06:49:23 pm
content: ""hence, why don't you try to pass examinations like ACM and SIGACT in computer science (university), and then find a job in avionics, ""who said I want to or need to. A tiny percentage of the code written needs that level of care. If you answer for everybody to need that then your answer is incorrect.which textbook will tell me what to do with #define and why casting a constant in there is bad.

author: IanB
author_rank: Super Contributor
timestamp: August 11, 2018, 07:12:48 pm
content: Quote from: legacy on August 11, 2018, 04:47:20 pmThere are two ways a program can fail:1. The program does not do what the programmer intended, due to faulty implementation and misunderstanding about how the programming system works;2. The program does exactly what the programmer intended, but the programmer's intentions were wrong.I see a lot of bugs of the second kind in my daily work. Does ADA have any tools to help prevent such bugs?

author: glarsson
author_rank: Frequent Contributor
timestamp: August 11, 2018, 07:47:40 pm
content: No. Ada doesn't even solve #1.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 11, 2018, 08:00:27 pm
content: reaching page 4 for what obviously #define is a solution... and i'm sorry for the OP reluctant to it...

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 11, 2018, 08:39:08 pm
content: Quote from: mikerj on August 11, 2018, 12:37:30 pmSo in the OP's scenario, unless the compiler is fairly smart, it would waste memory on the intermediate constants.#define would achieve exactly what was required on any compiler, however smart or dumb, and be understandable by any programmer, however smart or dumb.Seems to me like the optimum solution for the OP's situation.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 11, 2018, 08:41:42 pm
content: Quote from: legacy on August 11, 2018, 01:30:36 pmIt's a constant. You know what its value is, so doesn't affect debugging.

author: rstofer
author_rank: Super Contributor
timestamp: August 11, 2018, 09:03:59 pm
content: Just because a literal is #defined doesn't mean that it won't be allocated storage. The ARM does not have the ability to do a MOV of a literal to a register for certain values. You simply can't stuff a 32 bit value into a 32 bit instruction. This will be noticeable if the literal is -1 or 0xffffffff.I haven't checked to see how this is resolved. The issue is discussed here:http://www.keil.com/support/man/docs/armasm/armasm_dom1359731145835.htmI would expect the compiler to use an LDR to grab the value out of a literal pool. Since the value exists in the pool, it is theoretically possible to change it with a pointer to the address. Getting the address should be difficult, I hope!As to whether #define is evil incarnate, why not look at some production code and see if is used. Maybe the Linux kernel. Whatever those guys are doing is probably as close to 'normal' practices as it gets.Here's some kernel code from an ATA driver (because that is the first file I opened):Code:/** DaVinci DA850 AHCI SATA platform driver** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2, or (at your option)* any later version.*/#include <linux/kernel.h>#include <linux/module.h>#include <linux/pm.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/libata.h>#include <linux/ahci_platform.h>#include "ahci.h"#define DRV_NAME"ahci_da850"#define HARDRESET_RETRIES5/* SATA PHY Control Register offset from AHCI base */#define SATA_P0PHYCR_REG0x178#define SATA_PHY_MPY(x)((x) << 0)#define SATA_PHY_LOS(x)((x) << 6)#define SATA_PHY_RXCDR(x)((x) << 10)#define SATA_PHY_RXEQ(x)((x) << 13)#define SATA_PHY_TXSWING(x)((x) << 19)#define SATA_PHY_ENPLL(x)((x) << 31)...No big surprise... I would expect to see this type of thing in just about every file.Notice the parenthesis around x in the definition. This is critical!

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 11, 2018, 09:18:57 pm
content: Quote from: legacy on August 11, 2018, 09:06:55 pmThe microchip MPLABX editor auto-colours #if blocks, which makes that kind of thing a lot easierQuoteLike I said, more or less appropriate for a given situation... ISTR the OP is talking about a small MCU system, not a hugely complex piece of code like a router.At the end of the day you need to get the job done. Bonus points for readability and maintainability. More bonus points for not unnecessarily relying on clever features of particular compilers.The OP was more concerned about listening to "best practice" from "experts" than thinking about what was appropriate for his situation. That is the lesson to be learnt here.

author: rstofer
author_rank: Super Contributor
timestamp: August 11, 2018, 10:10:42 pm
content: Quote from: legacy on August 11, 2018, 10:05:13 pmThat sounds a lot like blaming the saw for the woodworker's mistake.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 11, 2018, 11:24:04 pm
content: Quote from: legacy on August 11, 2018, 09:06:55 pmprobably you are talking about #defines that are used for portability (does Ada have this feature in mind?) reason, that the same code be used in different router brand that doesnt have this and this functionality. not the #define the OP is talking about here... anyway... the code (or the original programmer) is twice the clever as you are... not me saying that...Quote from: Brian W. Kernighan

author: mikerj
author_rank: Super Contributor
timestamp: August 12, 2018, 11:37:28 am
content: Quote from: rstofer on August 11, 2018, 09:03:59 pmTrue, but this is architecture and value size specific. If you are using literals, you can't assume that it can be treated like a const. Even if possible, attempting to do so would be horrible.Quote from: legacy on August 11, 2018, 09:06:55 pmThis is when you would configure the compiler to save the preprocessed output when debugging.

author: donotdespisethesnake
author_rank: Super Contributor
timestamp: August 12, 2018, 03:31:06 pm
content: tldr;C is a terrible programming languageFew people really understand it

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 12, 2018, 04:49:23 pm
content: Quote from: donotdespisethesnake on August 12, 2018, 03:31:06 pmonly few people read the topic and OP and then chime in relevantly...

author: rstofer
author_rank: Super Contributor
timestamp: August 12, 2018, 08:25:51 pm
content: Quote from: mikerj on August 12, 2018, 11:37:28 amOr you wouldn't write that kind of stuff in the first place. My C compiler won't accept the '=' sign in the #define statements and I have no idea what the ellipsis expand to.It is possible to write poor code in any language. It isn't the fault of the language!There's a huge difference between using #define to do some bit of literal generation and trying to get it to expand multiple files into "War and Peace".

author: legacy
author_rank: Super Contributor
timestamp: August 13, 2018, 12:17:21 am
content: yeah, whatever, I have just found another *funny* abuse of macro in a chunk of abnormal working codethis line:Code:#define DIV(a,b) a / bWTF is the reason to #define it? and, worse still, why not in a safer way?Code:#define DIV(a,b) (a) / (b) /* safer version, well ... at least it does what is supposed to do */2411 lines below, there is this pretty chunk of code:Code:delta = DIV(x2,x1+2);and it's of course wrong: with x2=25, and x1=3, it gives the wrong result of 10, and not 5why? because the preprocessor expands it this way: (25 / 3) + 225/(3+2) != (25/3)+2, and the following if { .. } else { .. } is completely fucked up, hence under certain conditions this is the reason for the abnormal working of the firmware I was asked to fix up.Macros can't be debugged. When you have a macro that translates to a number or a string, the source code will have the macro name, and you can't "see" what the macro translates to. So you don't actually know what is going on. You need disassembly, and/or look at the hw-debugger.Thus, it hasn't been immediate to realize that macro can confuse people debugging the code, and yet again, I have just messed up three hours of my time for debugging

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 13, 2018, 12:51:14 am
content: Quote from: legacy on August 13, 2018, 12:17:21 am(exam) question.... whose fault?(a) the define(b) the programmerthe answer is.... let me guess... a person with ACM exam passed and designed a hybrid language will answer.... (a)

author: Nusa
author_rank: Super Contributor
timestamp: August 13, 2018, 12:55:33 am
content: // Finish the job of making it safer if you're going to do it at all// You need to isolate the entire result as well as the input parameters in the macro.// this would break your "safer" version. Modulo is same precedence as multiplication and divisiondelta = 100 % DIV(25,3);

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 13, 2018, 01:31:44 am
content: Then definetely (a)

author: mikerj
author_rank: Super Contributor
timestamp: August 13, 2018, 09:24:32 am
content: Quote from: rstofer on August 12, 2018, 08:25:51 pmThe example is nowhere near syntactically correct, but the gist of if should be clear. The ellipsis simply means that more code could follow.Quote from: rstofer on August 12, 2018, 08:25:51 pmYou are preaching to the converted, deeply nested #defines can be a nightmare to understand/debug for someone else looking at the code.

author: tggzzz
author_rank: Super Contributor
timestamp: August 13, 2018, 09:47:00 am
content: Ever get the feeling that modern C is part of the problem rather than part of the solution? C was good technology when I first used it in 1981

author: Ian.M
author_rank: Super Contributor
timestamp: August 13, 2018, 10:03:05 am
content: OTOH the ISO C++ standard committee didn't realise that C++ templates were actually a Turing complete language that executes at compile time. IMHO that's *WORSE* than the ANSI C preprocessor mess, with greater potential for inadvertent or deliberate obfuscation.

author: tggzzz
author_rank: Super Contributor
timestamp: August 13, 2018, 11:08:42 am
content: Quote from: Ian.M on August 13, 2018, 10:03:05 amHey! That'smyline! Glad to see someone is listeningThat debacle indicates the language was out of the comprehension of thelanguage designers, and it hasn't got better since! If mere users produce something that "works", then it is mere good fortune(We'll skate over the "difficulties" that debuggers have when there are templates and exceptions)

author: NorthGuy
author_rank: Super Contributor
timestamp: August 13, 2018, 01:41:21 pm
content: If you take a power nailer, youcandrive a nail into your foot and injury yourself. Or you can drive it into your eye and kill yourself. Does it make the power nailer less useful? or less safe? Of course not. You just don't drive nails into your body, and that's what keeps you safe.The same thing with computer languages (also macros, and everything else). Even if youcando stupid things, you don't have to. Computer languages are tools, just as the power nailer.

author: tggzzz
author_rank: Super Contributor
timestamp: August 13, 2018, 02:07:19 pm
content: Quote from: NorthGuy on August 13, 2018, 01:41:21 pmWhoosh!That's the sound of the key point whizzing past you, as you trot out a trite and unhelpful sound-bite.(Unless, of course, you want to argue that it is only to be expected that thedesignersof power nailers refused to acknowlege that it could be used to nail yourself - until after someone demonstrated that you could nail a person. Because the C++ template designersdidrefuse to acknowledge their creation was Turing complete until someone rubbed their faces in it)

author: legacy
author_rank: Super Contributor
timestamp: August 13, 2018, 02:33:09 pm
content: the above piece of code is the firmware of a laser-engraver, and it comes from a group of hipsters of the opensource, even if their products are closed-software.Quote from: Mechatrommer on August 13, 2018, 12:51:14 amThey have a cool and modern company building, with a tree-lined avenue at the entrance of the company, Mercedes business cars in front of a serious pop-art logo, and a couple of sexy girls at the reception, but I frankly doubt their "developers" have ever passed an ACM exam, since in order to pass the examination you have to understand and master the reason why abusing #define is bad.aka, if the examinator asks you to write a piece of code for the laboratory, and you write #define div(a,b) ... well, It's for sure the best way to relist your tired ass on the examination-chair six months lateranyway, their firmware also had other defects, got all fixed, got all the money, I can finally get my vacation

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 13, 2018, 03:10:46 pm
content: well if its that easy.. in fact i never have a need for #define div(a,b)... and i built few programs in VB which has no define feature let alone pointer, somewhat crippled but safer (i guess).... pascal/delphi too which i ditched long time ago. i think i can make the examiner happyotoh one thing for sure, i never come across a programming language or anybody claim that we can program at moderate complexity and it will run nicely at the first compile. if Ada is so good its should already be applauded by many serious developers around the globe and the epidemic should have infected us the "clueless" hobbiests here. isnt advancement in science should be had for free to public? why keep to Avionics?

author: andyturk
author_rank: Frequent Contributor
timestamp: August 13, 2018, 03:25:52 pm
content: Quote from: tggzzz on August 13, 2018, 02:07:19 pmWho cares?What difference does it make if the "C++ template designers" weren't perfect engineers. Who cares if they didn't set out to build aTuring-completemeta language, but discovered one along the way? Heck, I bet they suffered from bad breath and questionable politics too, but that doesn't affect the utility of what they created.Sometimes useful things are discovered rather than conceived. LikePenicillin, for example, orTeflon. You know, Astroglide was anaccidental discoverytoo.C++ is like Astroglide for programmers and I, for one, will not be going back to life without it.