Typedef не принимается в качестве типа данных в функции?
Я знаю, что работаю с компилятором C++, но обычно я создаю определение типа из структур, вероятно, пережитков более раннего программирования на C. Так что у меня кружится голова. Я создаю Typedef из структуры. После этого у меня нет проблем с объявлением глобальной или локальной версии этой структуры в любом месте функции или вне всех функций (глобально). Но когда я пытаюсь создать функцию с этим определением типа в качестве аргумента или даже функцию arg с указателем на такое определение типа, компилятор жалуется (и эта жалоба, похоже, не имеет смысла). Пример...
typedef struct ss_tag {
uint16_t settingsSavedCount;
uint16_t codeID;
// еще несколько переменных
uint8_t powerDownSaveFlag; // сообщает мне, почему происходит сброс.
uint8_t future[10];
} Sunstates;
Итак, теперь этот typedef кажется таким же хорошим, как и любой другой. Любой из этих операторов компилируется нормально...
Sunstates sunStates;
Sunstates * pSS = &sunStates;
Но если я теперь попытаюсь создать функцию либо с экземпляром этого типа данных, либо с указателем на него, вот так...
void systemDataVerify(Sunstates *pST) { }
Компилятор Arduino выдает это запутанное сообщение об ошибке...
Arduino: 1.8.3 (Windows XP), плата: «Arduino Nano, ATmega328»
SolarControler_21a:393: ошибка: переменная или поле «systemDataVerify» объявлен недействительным
void systemDataVerify(Sunstates *pSS) {
^
SolarControler_21a:393: ошибка: «Sunstates» не было объявлено в этом область применения
SolarControler_21a:393: ошибка: «pSS» не был объявлен в этой области
void systemDataVerify(Sunstates *pSS) {
статус выхода 1, переменная или поле 'systemDataVerify' объявлены недействительными
Тот факт, что мне не нравится объявление функции void, является странным, но не так тревожно, как то, что я называю мою функцию «переменной или полем», и определенно не так странно, как утверждение, что мой тип данных (Sunstates) НЕ " ;заявлено в этой области." Тип данных был определен непосредственно перед функцией... и тот факт, что я мог объявить оба экземпляра типа И указатели на него, как бы доказывает, что он существует в области видимости. Может кто-нибудь помочь мне понять, почему компилятор жалуется?
Изменить... Меня попросили добавить краткий набросок, показывающий проблему...
uint8_t somefunction() {
return;
}
// определяем структуру для хранения/сохранения информации о настройках и режиме
typedef struct ss_tag {
uint16_t settingsSavedCount;
uint8_t powerDownSaveFlag; // сообщает мне, почему происходит сброс.
} Sunstates;
Sunstates sunStates; // создаем экземпляр
// создаем функцию, принимающую указатель на
// введите Sunstates в качестве аргумента
void systemDataVerify(Sunstates *p) {
return;
}
void setup() {
// поместите сюда свой код установки для однократного запуска:
}
void loop() {
// поместите сюда свой основной код для многократного запуска:
}
Теперь... Я обнаружил, что если я удалю определение somefunction() перед определением структуры, проблема исчезнет. Для компиляции я использую Arduino 1.8.3.
@Randy, 👍2
Обсуждение3 ответа
Лучший ответ:
Я не получаю эту ошибку в Arduino IDE 1.8.5 с предоставленным вами фрагментом, но я получаю ее в плагине Sloeber Eclipse. Приложенный позже скетч также не компилируется в Arduino IDE 1.8.5.
Ошибка связана с преобразованием ino в cpp цепочки сборки Arduino для компиляции C++. Поместите объявление typedef в файл .h и включите его в ino.
РЕДАКТИРОВАТЬ: Подробности можно найти в моем новом ответе на аналогичную проблему.
Хм... ну, все, что я когда-либо использовал, это официальную версию Arduino 1.8.3 (хотя мне очень хотелось попробовать этот плагин Eclipse!). Ну, что ж, спасибо! Я попробую этот подход к файлу .H. Но тот факт, что он компилируется для ВАС, по крайней мере, говорит мне, что я не сумасшедший и что код ДОЛЖЕН компилироваться. На данный момент я нашел обходной путь... Я могу просто заставить свою функцию принимать void * , а затем в теле функции создать новый указатель на этот тип структуры и, наконец, привести переданный указатель void для его инициализации. . Кажется, это работает., @Randy
Я принимаю этот ответ, хотя я еще не обновил свою IDE, потому что размещение структуры и определения типа в верхней части файла (до объявления каких-либо функций, но после всех других файлов заголовков) решает проблему. Тем не менее, я обновил свой пост коротким наброском, который надежно иллюстрирует проблему, и мне было бы интересно получить подтверждение того, что ваша версия 1.8.5 скомпилирует ее без ошибок. Не то чтобы я не доверял улучшениям компилятора, но мой текущий проект настолько сложен, что регрессивное тестирование занимает очень много времени, поэтому я лучше приберегу это обновление на «черный день» :-), @Randy
прикрепленный эскиз также не работает в IDE 1.8.5, @Juraj
Но размещение структуры typedef в файле H работает? Если да, то между этим предложением и моим обходным путем у нас, по крайней мере, будет ответ., @Randy
да .х работает. это то же самое, что поместить typedef в начало ino, @Juraj
Итак, теперь остается единственный вопрос: если мой первоначальный эскиз не нарушал никаких правил C/C++, как вы думаете, может быть, мне стоит опубликовать это наблюдение на официальном форуме Arduino.cc? Кажется, там много людей, которые непосредственно работают над разработкой и могут быть заинтересованы в будущих исправлениях компилятора., @Randy
это проблема преобразования ino в cpp. покрытие делает, если я не ошибаюсь, arduino-builder https://github.com/arduino/arduino-builder, @Juraj
одна из вещей, которую делает строитель, — это предварительное объявление функций. моя гипотеза заключается в том, что ваш порядок функций, переменных и typedef приводит к неправильному порядку предварительных объявлений., @Juraj
Прошло 5 лет после ОП с той же проблемой. Я использую Arduino IDE Версия: 2.2.1 Дата: 2023-08-31T14:35:44.802Z. А я использую Adafruit ATSAMD21 M0.
Обратите внимание, что мой оскорбительный typedef уже находится в файле .h, помещая его после всего, что ему нужно, и перед любым использованием, поэтому это исправление у меня не работает.
Я обнаружил, как можно обойти эту проблему:
Изменение:
int storeXXX( framBlock *fb) {
На это:
int storeXXX( struct _framBlock *fb) {
То есть используйте для аргументов функции тип «реальный». Typedef везде выглядит нормально: локальные, глобальные, до и после точки отчета об ошибке и т. д. Только не в качестве аргумента функции.
Обратите внимание, что ОП нашел аналогичное решение, используя void * в качестве типа указателя typedef. Я не видел упоминаний об использовании типа «real», который является более простым решением.
По моему мнению, это ошибка компилятора. Возможно, это следует передать составителям.
См. мой ответ., @Nick Gammon
Это не ошибка компилятора, @alm.
Если я возьму Минимальный воспроизводимый пример, предоставленный OP, и скомпилирую его, а затем посмотрю промежуточный файл, созданный IDE (а не компилятором), вы можете увидеть, что происходит:
#include <Arduino.h>
#line 1 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
#line 1 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
#line 1 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
uint8_t somefunction();
#line 18 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
void systemDataVerify(Sunstates *p);
#line 22 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
void setup();
#line 26 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
void loop();
#line 1 "/home/nick/Arduino/typedef_issue/typedef_issue.ino"
uint8_t somefunction() {
return;
}
// определяем структуру для хранения/сохранения информации о настройках и режиме
typedef struct ss_tag {
uint16_t settingsSavedCount;
uint8_t powerDownSaveFlag; // сообщает мне, почему происходит сброс.
} Sunstates;
Sunstates sunStates; // создаем экземпляр
// создаем функцию, принимающую указатель на
// введите Sunstates в качестве аргумента
void systemDataVerify(Sunstates *p) {
return;
}
void setup() {
// поместите сюда свой код установки для однократного запуска:
}
void loop() {
// поместите сюда свой основной код для многократного запуска:
}
Вы заметите, что IDE "услужливо" создает прототипы функций для ваших функций, и порядок, в котором это делается, означает, что прототип для void systemDataVerify(Sunstates *p);
перед typedef для структуру, что приводит к сообщению об ошибке.
Решение простое. Поместите собственный прототип функции в исходный код, таким образом сообщив IDE, чтобы она не беспокоилась, например:
uint8_t somefunction() {
return;
}
// определяем структуру для хранения/сохранения информации о настройках и режиме
typedef struct ss_tag {
uint16_t settingsSavedCount;
uint8_t powerDownSaveFlag; // сообщает мне, почему происходит сброс.
} Sunstates;
void systemDataVerify(Sunstates *p); // <<<<<< ---- тип прототипа функции
Sunstates sunStates; // создаем экземпляр
// создаем функцию, принимающую указатель на
// введите Sunstates в качестве аргумента
void systemDataVerify(Sunstates *p) {
return;
}
void setup() {
// поместите сюда свой код установки для однократного запуска:
}
void loop() {
// поместите сюда свой основной код для многократного запуска:
}
По моему мнению, это ошибка компилятора. Возможно, это следует передать составителям.
Это не ошибка компилятора, возможно, это особенность работы IDE. Нет смысла отправлять отчеты об ошибках авторам компиляторов. Вы могли бы поднять вопрос на Github для IDE, жалуясь на то, как они генерируют прототипы функций.
Для получения дополнительной информации см. мой ответ здесь. В нем я упоминаю:
Однако генерация прототипа функции может привести к появлению непонятных сообщений об ошибках, если вы не будете осторожны.
Ужасный генератор прототипов автоматических функций снова наносит удар!, @6v6gt
Сделайте, пожалуйста, небольшой набросок, показывающий проблему. Он компилируется, когда я пытаюсь сделать небольшой эскиз., @Jot
Проверьте синтаксис всего, что предшествует определению вашей функции. Похоже, что компилятор потерял синхронизацию и не ожидает, что здесь начнется определение функции. Можете ли вы в качестве проверки вместо этого определить здесь _другую_ функцию?, @JRobert
Ну, на самом деле до этого у меня была очень сложная функция, и проект уже был довольно огромным. Вот почему я создал такой небольшой набросок, чтобы изолировать проблему, с самой простой функцией, которую только мог придумать. до этого на самом деле ничего нет. Было достаточно легко исключить все функции до моей структуры, но на данный момент это похоже на ошибку компилятора., @Randy