0

IDE: MPLAB X v2.15

CC: XC8 v1.32

Target device: PIC18f45k20

I have a header file reg.h, which contains a variable

static const int aaasdf = 3;

That header has proper include guards at the beginning:

#ifndef PRJ_REG_H
#define PRJ_REG_H

And at the end:

#endif

If I have that same variable on any other header file, it compiles fine, but when that variable is in this particular file, it gives me error: (845) symbol "reg@aaasdf" defined more than once

But if I comment that variable, it doesn't exist anymore, and it complains because I need it in some .c file.

The strange name is just for testing, to be sure that there isn't any other variable with the same name.

What else can I do to debug this?

EDIT:

It does it for any static const variable, (I'll test tomorrow for only static, const or extern const), that I create in that file, but there are also enums, and static inline functions, and none of them gives me the repeated symbol error.

EDIT:

I think it's the compiler that is broken:

I removed everything from the header and also the source files. Now main is an infinite loop, and all is like that.

The headers are empty but for the variable triggering the error.

No header of mine includes any other header of mine.

What triggers the error: Any header that is included in many source files, and contains a static const variable of any type. What I mean by many is that if I include the header only in its source file and another file, it doesn't trigger the error, but if it is included in 2 source files that aren't its source file, it triggers the error.

EDIT:

As requested, here is a MCV example of what I want (not the compile error):

// reg.h

enum    Reg_OSCCON_IRCF_Values {
    REG_OSCCON_IRCF_FREQ_31_KHZ = 0x0u,
    REG_OSCCON_IRCF_FREQ_250_KHZ    = 0x1u,
    REG_OSCCON_IRCF_FREQ_500_KHZ    = 0x2u,
    REG_OSCCON_IRCF_FREQ_1_MHZ  = 0x3u,
    REG_OSCCON_IRCF_FREQ_2_MHZ  = 0x4u,
    REG_OSCCON_IRCF_FREQ_4_MHZ  = 0x5u,
    REG_OSCCON_IRCF_FREQ_8_MHZ  = 0x6u,
    REG_OSCCON_IRCF_FREQ_16_MHZ = 0x7u
};
#define REG_OSCCON_IRCF_FREQ        ((const uint32_t [8]){      \
                           31000u,      \
                          250000u,      \
                          500000u,      \
                         1000000u,      \
                         2000000u,      \
                         4000000u,      \
                         8000000u,      \
                        16000000u       \
                    })

static inline   void reg_field_set(volatile uint8_t *reg,
                uint8_t mask, uint8_t posn, uint8_t val)
{

    *reg    = (*reg & ~mask) | ((val << posn) & mask);
}

static inline   void reg_OSCCON_IRCF_set(uint8_t val)
{

    reg_field_set(&OSCCON, _OSCCON_IRCF_MASK, _OSCCON_IRCF_POSN, val);
}

// pwm.c

#include "reg.h"
extern uint32_t sys_freq;

int foo(/**/)
{
    static const uint32_t   freq_min =
        REG_OSCCON_IRCF_FREQ[REG_OSCCON_IRCF_FREQ_16_MHZ] /
        (UINT8_MAX * 4 *
        REG_T2CON_T2CKPS_PRESCALER[REG_T2CON_T2CKPS_PRESCALER_1]);

    reg_OSCCON_IRCF_set(REG_OSCCON_IRCF_FREQ_16_MHZ);
    sys_freq    = REG_OSCCON_IRCF_FREQ[REG_OSCCON_IRCF_FREQ_16_MHZ];
    // ...
}

Option 1: As showed above, using a macro that expands to a const compound array literal, where I can access any of its elements (either at compile time or at run time). Need C99, which I don't have. EDIT: const compound literals may or may not be constant expressions (Initialize static variable with element of const compound literal), and therefore may or may not be valid as initializers for static variables.

Option 2: Changing the macro to a static const array. Pros: don't need C99. Cons: Can NOT initialize a static variable. The compiler seems broken and doesn't allow me to do that.

Option 3: Magic numbers. Pros: Don't need C99. Can initialize a static variable. Cons: Magic numbers.

Option 4: A lot of macros (for each of the arrays, because it's not only this one!). Pros: Don't need C99. Cons: Polluting global namespace.

  • 2
    please post a [mcve] that shows the error – user3629249 Feb 07 '19 at 00:43
  • The last paragraph would be that. Isn't it? – alx - recommends codidact Feb 07 '19 at 10:23
  • You should know that a variable instance should NEVER be declared in a header file. Your question brings up a prime example of why that is true. Much better to declare the variable in a .c file and have the header file use `extern` to reference that variable. However, since the variable is `static` it should not be known anywhere except the file that declares it. (that's why the variable would be marked 'static' – user3629249 Feb 07 '19 at 19:08
  • The reason I need a variable in the header is that I need an array of constants (In the real case it's not a variable, but an array, but the error is the same). And I would do that with a macro that expands to a compound array literal, but that shit of compiler doesn't have `C99` support (although it has *an incomplete* ``), so the only way I've found to accomplish that is though `static const` arrays. However it seems that the compiler won't even allow me to do that. The only options left would be to have a lot of macros (undesirable), or magic numbers with comments. – alx - recommends codidact Feb 07 '19 at 20:30
  • Aside: Untill now I always preferred macros over `static const`s, but didn't really know why, but yesterday I found a very very good reason: `static const`s can NOT be used to initialize `static` variables. – alx - recommends codidact Feb 07 '19 at 20:35
  • Please post a [mcve] that demonstrates the problem that you are trying to solve. I.E. not a repeat of the compile problem, but rather the problem that you are trying to solve – user3629249 Feb 07 '19 at 20:36
  • 1
    `xc8` ugh, had only problems with it. What's the point of `REG_OSCCON_IRCF_FREQ_16_MHZ` ? Can't it be just `#define REG_OSCCON_IRCF_FREQ_16_MHZ 16000000u` ? I remember that `xc8` has problems calculating integers constants, I would advise to suffix with `ull`. But i need to say it: find a trash bin, put the pic18 there, buy cheaper stm32 and move to gcc. Are you using the free version of xc8? You can make the `REG_OSCCON_IRCF_FREQ` to just be a static array, which will actually save more memory. On a decent compiler. With optimizer. – KamilCuk Feb 07 '19 at 21:34
  • I have STM32 L4 and F0, but this is part of a subject :( – alx - recommends codidact Feb 07 '19 at 21:46
  • `REG_OSCCON_IRCF_FREQ_16_MHZ`: this macro is the value that I need to write into the `IRCF` field of the `OSCCON` register to change to a sysclk frequency of 16 MHz, and therefore the line `reg_OSCCON_IRCF_set(REG_OSCCON_IRCF_FREQ_16_MHZ);` After that, I change the variable `sys_freq` which is a variable that I created to remember what is the current frequency of the clk. – alx - recommends codidact Feb 07 '19 at 21:48
  • Why would I need the `ULL`? First, it is `C99` so I'm not sure the compiler will understand it, and second, a constant integral is guaranteed to not overflow itself, isn't it? And third, that shit doesn't even accept `uint_least64_t` so I don't think it will accept `unsigned long long`. I wish I had GCC here, or at least that SDCC was stable enough to use it. – alx - recommends codidact Feb 07 '19 at 21:53
  • Yes, I think it's the free version of XC8, but I'm not sure (I don't have the school PC here). Not only that, but I'm limited to an old version of it because the template for this PIC doesn't even compile with the new version of XC8. – alx - recommends codidact Feb 07 '19 at 22:00
  • For a `static` array (I guess also `const`), are you talking about option 2 above? That wouldn't allow me to initialize `static`variables. Also, `const` compound literals that are the same are allowed to share memory, so in the end it should be using the same memory (with a decent compiler, which XC8 isn't) – alx - recommends codidact Feb 07 '19 at 22:03

1 Answers1

0

Definitely the XC8 compiler is broken.

Today similar errors appeared when using static inline functions. I've googled about it, and it seems the compiler isn't very good with that kind of code.