glados
glados

Reputation: 33

Forcing compiler to make arithmetic calculations during preprocess

Compiler: MPLABX IDE V5.30
Operating system: Windows 10

What I’m trying to do is define some constant values (to make future changes easier) and create some other constants via arithmetic operations during preprocessing. Then use those constants during runtime.

Here is an example version of my intentions;

#include <stdio.h>
#include <math.h>

#define foo 100 // In case you change FOO in circuit, change this too!
#define bar (sqrt(foo))

int main(void) {
    if ( bar > user_input)
    {
        do();
    }
}

The problem is, I thought, since the input was a constant value, defined things would be calculated by the compiler and bar would be replaced by 10 instead of (sqrt(foo)). But when I compiled it, data and program size dramatically changed. When I disassembly it, there are tons of instructions instead of simply putting directly a number there.

Then I followed a suggestion from another question's answer and place a const squareroot() function and const int declaration, but the compiler gave an alert like;

main.c:50:38: error: initializer element is not a compile-time constant

Here is the second try;

#include <stdio.h>
#include <squareroot.h>

#define foo 100 // In case you change FOO in circuit, change this too!
const int bar = squareroot(foo);

int main(void) {
    if ( bar > user_input)
    {
        do();
    }
}

const int squareroot(const int input)
{
    do()
}

How can I express myself to my compiler to make it understand some of the lines in my code are constant whatever happens during runtime, so that it can do the arithmetic instead of just simply passing the token/text to the function body?

Upvotes: 3

Views: 595

Answers (3)

0___________
0___________

Reputation: 67820

Most of the decent compilers will do it for you.

https://godbolt.org/z/6f5Awz

#define foo 100 // In case you change FOO in circuit, change this too!
#define bar (sqrt(foo))

volatile int x;

int main(void) {
    x = bar;
}

And the result:

x:
        .zero   4
main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR x[rip], 10
        mov     eax, 0
        pop     rbp
        ret

The only question is if the MPLAB is a decent compiler. At least in the free version it is not. Microchip intentionally makes the generated code worse to force your buying decisions. If you decided to use PIC microcontrollers, you don't have any chance only to buy that "product".

Upvotes: 3

cup
cup

Reputation: 8267

You could tackle the problem the other way round. You know that the compiler cannot handle functions but all compilers can handle multiplication. Since sqrt(x)*sqrt(x) = x

#define bar (10)
const int foo = bar * bar;

This will give you a compile time constant for foo on any compiler. Unfortunately I don't know how to paste the output of the XC8 compiler to a web browser so I can't show you the result. Alternatively, don't bother with #define.

const int bar = 10;
const int foo = bar * bar;

If you have to patch the code, during debugging, you only need to patch the values for bar and foo. With #defines, you will need to patch it wherever the #define is used. If foo is a number which causes bar to be a floating point number then you will have to do both values

const int bar = 9;
const int foo = 90; /* bar * bar */

Upvotes: 0

M.M
M.M

Reputation: 141628

#define is a plaintext replacement and nothing more. All of the #define transformations occur in the preprocessing translation phase which is before any analysis of expressions and so on.

The list of which expressions the compiler must support in a constant expression can be found in section 6.6 of the current C Standard, for a summary see here. Calling a function is not included.

(Of course, individual compilers may offer features not required by the Standard).

If you must use a compiler which does not support calling the floating point function sqrt in a constant expression then your options include:

  • Hardcode your constants, runing another preprocessing phase to set them up if desirable.
  • Have a global variable which you initialize at the start of the main function .

Upvotes: 4

Related Questions