3

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 compile 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 aritmetic instead of just simply passing the token/text to the function body?

kudagaci
  • 33
  • 3
  • 1
    the problem is `sqrt` is not a simple function that makes sense for the compiler to take care of for you. – Christian Gibbons Jun 22 '20 at 22:23
  • 4
    `#define bar 10 // if you change the line above, change this line to be the square root` – user3386109 Jun 22 '20 at 22:27
  • @ChristianGibbons for compiler it is. gcc and other decent compiler will know what it is. – 0___________ Jun 22 '20 at 22:31
  • @ChristianGibbons I also read this on another thread. But what i can't understand is, even if it's relatively not a simple question, it can be compiled with C language, and return a square root of a number normally. And no matter how many times i run it, it would give the same result, since it's only input is a constant number. So why would a compiler precalculate it to ease the workload of runtime? are there any workarounds to force it? Or are there some restrictions about it? – kudagaci Jun 22 '20 at 22:32
  • @kudagaci do you have a fully licenced version? (ie not free) – 0___________ Jun 22 '20 at 22:35
  • @kudagaci decent compilers do it. – 0___________ Jun 22 '20 at 22:36
  • I stand corrected. – Christian Gibbons Jun 22 '20 at 22:38
  • @P__J__ well it was free. But I spend few hours for this issue, if it counts as some currency, – kudagaci Jun 22 '20 at 22:46
  • As free it does not optimize anything. – 0___________ Jun 22 '20 at 22:47
  • @user3386109 is should be as autonomous as it can get. What's the reason of using a computer if you still have to process that same thing with your brain after uploading your thoughts to that machine? – kudagaci Jun 22 '20 at 22:54
  • 1
    @kudagaci you could make a solid argument that the reason C became such a dominant language was that the language definition is relatively simple and does not mandate any compiler vendor to perform some collection of micro-optimizations. Compile-time floating point operations as you request here quickly becomes non-trivial when you consider that the source and target systems may have different levels of precision and rounding modes . – M.M Jun 22 '20 at 23:20
  • @kudagaci The computer will be happy to do the calculation for you, if you follow the rules of the language. You don't get to reinvent the language just to fit your particular use case. – user3386109 Jun 23 '20 at 00:29

3 Answers3

4

#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 .
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/216466/discussion-on-answer-by-m-m-forcing-compiler-to-make-arithmetic-calculations-dur). – Jean-François Fabre Jun 23 '20 at 05:47
3

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 uCs you have no chance only to buy that "product".

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 1
    Granted - decades ago - but in my PIC projects, I used assembler. If your problem is trivial enough, this might still be a "cheap" alternative to buying the C compiler. – BitTickler Jun 22 '20 at 22:36
  • 2
    The best choice is: not use PICs – 0___________ Jun 22 '20 at 22:36
  • Thank you! Wish i could give my upvote now but since this is my first post, i'll make you wait a while... Even though compiler can't do it itself, is there a method to make compiler understand things are constant and force it to be done at preprocess? Also a second question. Would you suggest GCC instead of MPLABX for PIC or KEIL for ARM? I've never used it so far but heard a lot. – kudagaci Jun 22 '20 at 22:43
  • I do not use PICs. I do use gcc for my ARM uC programming (It is my daytime job). I have keil and IAR but personally prefer gcc – 0___________ Jun 22 '20 at 22:45
0

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 */
cup
  • 7,589
  • 4
  • 19
  • 42