Символьный файл@переменная определена более одного раза

IDE: MPLAB X v2.15

CC: XC8 v1.32

Целевое устройство: PIC18f45k20

У меня есть заголовочный файл reg.h, который содержит переменную

static const int aaasdf = 3;

Этот заголовок имеет правильное включение защиты в начале:

#ifndef PRJ_REG_H
#define PRJ_REG_H

И в конце:

#endif

Если у меня есть такая же переменная в любом другом заголовочном файле, она компилируется нормально, но когда эта переменная находится в этом конкретном файле, она дает мне error: (845) symbol "reg@aaasdf" defined more than once

Но если я прокомментирую эту переменную, ее больше не будет, и она жалуется, потому что она нужна мне в каком-то файле .c.

Странное имя просто для тестирования, чтобы убедиться, что нет другой переменной с таким же именем.

Что еще я могу сделать, чтобы отладить это?

ИЗМЕНИТЬ:

Он делает это для любой переменной static const (завтра я проверю только для static, const или extern const), которую я создаю в этом файле, но есть также функции enums и static inline, и ни одна из них не дает мне повторяющуюся ошибку символа .

ИЗМЕНИТЬ:

Я думаю, что компилятор сломан:

Я удалил все из шапки, а также исходные файлы. Теперь main — это бесконечный цикл, и все в таком духе.

Заголовки пусты, но для переменной, вызывающей ошибку.

Ни один из моих заголовков не включает другие мои заголовки.

Что вызывает ошибку: Любой заголовок, включенный во многие исходные файлы и содержащий переменную static const любого типа. Под многими я подразумеваю, что если я включу заголовок только в его исходный файл и другой файл, он не вызовет ошибку, но если он будет включен в 2 исходных файла, которые не являются его исходным файлом, он вызовет ошибку .

ИЗМЕНИТЬ:

В соответствии с запросом, вот пример MCV того, что я хочу (не ошибка компиляции):

// 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
#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];
    // ...
}
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];
    // ...
}

Вариант 1: как показано выше, с помощью макроса, который расширяется до литерала составного массива const, где я могу получить доступ к любому из его элементов (либо во время компиляции, либо во время выполнения). Нужен C99, которого у меня нет. EDIT: const составные литералы могут или не могут быть константными выражениями (Инициализировать статическую переменную элементом составного константного литерала), поэтому может или может не использоваться в качестве инициализатора для static переменных.

Вариант 2: изменение макроса на массив static const. Плюсы: не нужно C99. Минусы: НЕ МОЖЕТ инициализировать переменную static. Компилятор кажется сломанным и не позволяет мне это сделать.

Вариант 3: Магические числа. Плюсы: Не нужно C99. Может инициализировать переменную static. Минусы: магические числа.

Вариант 4: Много макросов (на каждый из массивов, ведь не только на этот!). Плюсы: Не нужно C99. Минусы: Загрязнение глобального пространства имен.


person alx    schedule 06.02.2019    source источник
comment
опубликуйте минимально воспроизводимый пример, который показывает ошибку   -  person user3629249    schedule 07.02.2019
comment
Последний абзац будет таким. Не так ли?   -  person alx    schedule 07.02.2019
comment
Вы должны знать, что экземпляр переменной НИКОГДА не должен быть объявлен в заголовочном файле. Ваш вопрос является ярким примером того, почему это так. Гораздо лучше объявить переменную в файле .c, а файл заголовка использовать extern для ссылки на эту переменную. Однако, поскольку переменная static, она не должна быть известна нигде, кроме файла, в котором она объявлена. (поэтому переменная будет помечена как «статическая»   -  person user3629249    schedule 07.02.2019
comment
Причина, по которой мне нужна переменная в заголовке, заключается в том, что мне нужен массив констант (в реальном случае это не переменная, а массив, но ошибка та же). И я бы сделал это с помощью макроса, который расширяется до литерала составного массива, но у этого дерьмового компилятора нет поддержки C99 (хотя у него есть неполный <stdint.h>), так что единственный способ, которым я нашел для выполнения, что есть хоть static const массивы. Однако кажется, что компилятор даже не позволит мне это сделать. Единственным оставшимся вариантом было бы иметь много макросов (нежелательно) или магические числа с комментариями.   -  person alx    schedule 07.02.2019
comment
В сторону: до сих пор я всегда предпочитал макросы static consts, но не знал, почему, но вчера я нашел очень и очень вескую причину: static consts нельзя использовать для инициализации static переменных.   -  person alx    schedule 07.02.2019
comment
Опубликуйте минимально воспроизводимый пример, демонстрирующий проблему, которую вы пытаетесь решить. т.е. не повторение проблемы компиляции, а проблема, которую вы пытаетесь решить   -  person user3629249    schedule 07.02.2019
comment
xc8 тьфу, были только с этим проблемы. Какой смысл в REG_OSCCON_IRCF_FREQ_16_MHZ ? Разве это не может быть просто #define REG_OSCCON_IRCF_FREQ_16_MHZ 16000000u ? Я помню, что у xc8 есть проблемы с вычислением целочисленных констант, я бы посоветовал добавить суффикс с ull. Но я должен сказать это: найдите мусорное ведро, положите туда pic18, купите более дешевый stm32 и перейдите на gcc. Вы используете бесплатную версию xc8? Вы можете сделать REG_OSCCON_IRCF_FREQ просто статическим массивом, что на самом деле сэкономит больше памяти. На приличном компиляторе. С оптимизатором.   -  person KamilCuk    schedule 08.02.2019
comment
У меня есть STM32 L4 и F0, но это часть темы :(   -  person alx    schedule 08.02.2019
comment
REG_OSCCON_IRCF_FREQ_16_MHZ: этот макрос - это значение, которое мне нужно записать в поле IRCF регистра OSCCON для изменения на частоту sysclk 16 МГц, и, следовательно, строку reg_OSCCON_IRCF_set(REG_OSCCON_IRCF_FREQ_16_MHZ); После этого я изменяю переменную sys_freq, которая является переменной, которую я создал запомнить, какова текущая частота clk.   -  person alx    schedule 08.02.2019
comment
Зачем мне ULL? Во-первых, это C99, поэтому я не уверен, что компилятор его поймет, а во-вторых, константный интеграл гарантированно не переполнится, не так ли? И в-третьих, это дерьмо не принимает даже uint_least64_t, поэтому я не думаю, что оно примет unsigned long long. Хотел бы я, чтобы здесь был GCC, или, по крайней мере, SDCC был достаточно стабилен, чтобы его использовать.   -  person alx    schedule 08.02.2019
comment
Да, я думаю, что это бесплатная версия XC8, но я не уверен (у меня здесь нет школьного ПК). Мало того, я ограничен старой версией, потому что шаблон для этого PIC даже не компилируется с новой версией XC8.   -  person alx    schedule 08.02.2019
comment
Для массива static (я думаю, также const) вы говорите о варианте 2 выше? Это не позволило бы мне инициализировать staticvariables. Кроме того, const составным литералам, которые одинаковы, разрешено совместно использовать память, поэтому, в конце концов, они должны использовать одну и ту же память (с приличным компилятором, которого нет в XC8)   -  person alx    schedule 08.02.2019


Ответы (1)


Определенно компилятор XC8 неисправен.

Сегодня подобные ошибки появились при использовании static inline функций. Я гуглил об этом, и кажется, что компилятор не очень хорошо работает с таким кодом.

person alx    schedule 13.02.2019