Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

Если я умножаю/делю/складываю дефайновские константы, то все эти операции делает препроцессор и в код ничего не идет
Так это надо делать (умножать/делить) в основном файле, а в библиотеку передать результат. На то она и библиотека. Иначе в другим проекте можете напороться на то, что эти задефайненные выражения придётся править в библиотеке.
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

aam писал(а):Если я умножаю/делю/складываю дефайновские константы, то все эти операции делает препроцессор и в код ничего не идет.
Ничего в дефайнах не вычисляется. Дефайны только подменяют один текст на другой, и всё.
Код:

Код: Выделить всё

#define    a          10

int b=a*100;
Еквивалентен этому:

Код: Выделить всё

int b=10*100;
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Да, препроцессор только подставляет текст.

А уже дальше работает оптимизация у компилятора. И результаты арифметических действий над константами представляются в виде одной константы.

Вот я эксперимент даже провёл. main.c:

Код: Выделить всё

#include <stdio.h>

#define A 2
#define B 3
#define C (A + B)

int main(void)
{
	printf("%d\n", C);
	return 0;
}
Результат работы препроцессора (gcc -E), исключая то, что было подставлено из #include <stdio.h>:

Код: Выделить всё

int main(void)
{
 printf("%d\n", (2 + 3));
 return 0;
}
Контактная информация:
aam
Собутыльник Кота
Аватара пользователя
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Сообщение aam »

Извиняюсь, выразился не правильно - компилятор вычисляет, но естественно код для констант не генерит.

А что за ошибка e27 ?
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

aam писал(а):

Код: Выделить всё

Error[e27]: Entry "RC5_bit_cnt" in module LED_menu ( c:\firmware844\Debug\Obj\LED_menu.r90 ) redefined in module RC5 ( c:\firmware844\ Debug\Obj\RC5.r90 )
у вас в двух модулях LED_menu и RC5 объявляется одна и та же переменная RC5_bit_cnt
Ставим плюсы: )
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев

Сообщение BCluster »

Какое расточительство... Ерунда все это. С таким подходом на ассемблере пишите.
Насчет тини13 - если используется такой МК, то к нему можно специальный подход применить.
Насчет ошибки - вероятно вы не воспользовались рекомендациями, защищающими от множественного инклюда
Контактная информация:
Реклама
aam
Собутыльник Кота
Аватара пользователя
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Сообщение aam »

Да вот не объявлена... Хотя до того как стал с h-файломи и сишниками разбираться, все компилировалось :)))

Всем воспользовался конечно. Типа так:

Код: Выделить всё

#ifndef _RC5_H_INCLUDED_
#define _RC5_H_INCLUDED_ 1

.....

#endif
В сишниках естественно этого нет.

Я вот что-то не вдуплю, а я могу вообще глобальные переменные объявлять в нескольких h-файлах?? Скажем, в одной библиотеке объявил, в другой объявил, в главном h-файле проги объявил...
Че-то байда полная выходит... И мне начинает казаться что из-за этого именно((

И что интересно, логично - что в главном модуле он находит глобальную переменную из библиотки RC5/
Собутыльник Кота
Аватара пользователя
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев

Сообщение BCluster »

aam писал(а):Я вот что-то не вдуплю, а я могу вообще глобальные переменные объявлять в нескольких h-файлах??
Разные переменные я надеюсь? :) Или одну и ту же?
Вообще зачем переменные объявлять в h файле? Если переменная глобальная, она должна быть прописана в h файл как extern. А объявлять ее надо в с файлах.
aam писал(а):И что интересно, логично - что в главном модуле он находит глобальную переменную из библиотки RC5/
На то она и глобальная. Во всех модулях она будет видна. Если нужна переменная только в одном модуле, ее следует объявить как static
Контактная информация:
aam
Собутыльник Кота
Аватара пользователя
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Сообщение aam »

BCluster писал(а):Разные переменные я надеюсь?
Естественно!
Да и вообще эта переменная объявлена только в одном месте в проге.

Так, а что тогда модулем считать? Насколько я понимаю, есть сегмент данных - в нем глобальные переменные. Есть стек - в нем создаются локальные, т. е. те, которые объявлены внутри функции. Если я внутри функции заюзал спецификатор статик, то переменная тоже локальная, только что лежит в сегменте данных.
Что же касается глобальных, то как я понял, все что объявлено вне функций - глобально.
Т. е. написал я в сишнике: unsigned char a; - ее будет видно из любой другой функции. Но видно ли из другого файла?
Еще вопрос: если у меня там инлайн-функции в разных библиотеках, а компилятор по отдельности компилит сишники и потом модули собирает линкер. То как функции будут инлайниться? А ведь у меня полно в проге "одноразовых" функций типа Init_MCU() или sys_loop() и т. п. которые вызываются во всей проге только 1 раз и в 1 месте и созданы только для того, чтоб не снесло башню от объема и вида кода - чисто чтоб читаемо было. А ведь компилер там push/pop в каждую напихает непонятно нахрена.
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Я вот что-то не вдуплю, а я могу вообще глобальные переменные объявлять в нескольких h-файлах??
Объявлять - да. Определять - нет.

Как понимает компилятор:

Код: Выделить всё

extern uint8_t foo;
"Где-то есть переменая foo, беззнаковая, размером 1 байт, не пугайся ее, если встретишь, линкер разберется".

Код: Выделить всё

uint8_t foo;
"Заведи мне переменную foo, беззнаковую, размером 1 байт".

Первая конструкция в заголовочных файлах допустима и правильна, вторая - нет. Ибо как только компилятор натыкается на определение переменной, он пытается завести ее, выделить память и т.п. Разумеется, если он находит две переменные с одинаковым именем, он изумляется и выкидывает ошибку.

Потому заводят переменные в .c-файлах, а объявляют - в .h.
unsigned char a; - ее будет видно из любой другой функции. Но видно ли из другого файла?
Да, если эту переменную не объявить, ВНЕЗАПНО, как static.
а что тогда модулем считать?
Комплект .c + .h.
переменная объявлена только в одном месте в проге.
Если файл, в котором она объявлена, включается в две единицы компиляции - то считайте, что она объявлена два раза. Видимо, у вас так и есть.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

Т. е. написал я в сишнике: unsigned char a; - ее будет видно из любой другой функции. Но видно ли из другого файла?
Добавляете в заголовочник extern unsigned char a; и везде, где он подключен, переменную будет видно.
А ведь компилер там push/pop в каждую напихает непонятно нахрена.
Тут интересный момент: если инлайн-функция встречается в коде один раз, при включенной оптимизации ничто не мешает компилятору включить её в общую простыню инструкций. Не знаю, как обстоит на самом деле, надо почитать.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Возможно, переменная объявлена в .h-файле (хотя так делать не стоит, h-файлы предназначены для объявлений функций, дефайнов и описания структур). И этот файл инклюдится сразу двумя c-файлами. Соответственно, линкер видит сразу две глобальные переменные с одним именем.
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 848
Зарегистрирован: Ср мар 02, 2011 07:47:39
Откуда: Уфа

Сообщение Psych »

aam писал(а):Что же касается глобальных, то как я понял, все что объявлено вне функций - глобально.
Все что объявлено вне фигурных скобок!!
Мучитель микросхем
Аватара пользователя
Сообщения: 424
Зарегистрирован: Сб авг 25, 2007 22:02:05
Откуда: Германия, Viernheim

Сообщение unalex »

BCluster писал(а):Так, а что тогда модулем считать?
смысл таков

проект разбивается на функциональные блоки
например
- инициализация портов(init.h, init.c)
- измерение температуры(temp.h, temp.c)
- отсчет времени(time.h, time.c)
- вывод на дисплей(LCD.h, LCD.c)

и естественно главный модуль проекта(projectname.c), projectname.h в принципе не нужен. т.к. все объявления осуществляются в модулях

в xxx.h соответсвующих модулей объявляются характерные для них функции, в xxx.с эти функции реализуются

в главный проект включаются заголовки модулей, объявляются глобальные переменные, и собственно реализуется функционал всего проекта
Коктейль "Рекурсивный": 20% спирта, 30% воды, 50% коктейля "Рекурсивный"...
aam
Собутыльник Кота
Аватара пользователя
Сообщения: 2994
Зарегистрирован: Сб фев 20, 2010 14:00:12
Откуда: Москва

Сообщение aam »

Так у меня есть переменные, которые относятся не к какой-то конкретной функции, а ко всему девайсу.
И соответственно у меня есть файл main.c и projectname.h к нему. В этом h все общие переменные, инклюды и дефайны.
YS писал(а):Если файл, в котором она объявлена, включается в две единицы компиляции - то считайте, что она объявлена два раза. Видимо, у вас так и есть.
Защита от двойного включения во всех h-файлах естественно написана.

Специально сделал поиск по всем файлам - запись вида "unsigned char a;" есть только в файле RC5.h Этот файл никуда кроме projectname.h и RC5.c не инклюдится.
Короче, я так понял. Переменные я вс-таки должен объявлять ("unsigned char a;") именно в соответствующем сишнике (RC5.c). Тогда те из переменных, которые я хочу использовать другими модулями (файлами) проги, я должен дополнительно описать ("extern unsigned char a;") в h-файле. Те, которые сугубо личные и юзаются только внутри библиотеки - соответственно не описываю. Так?
ploop писал(а):Тут интересный момент: если инлайн-функция встречается в коде один раз, при включенной оптимизации ничто не мешает компилятору включить её в общую простыню инструкций. Не знаю, как обстоит на самом деле, надо почитать.
Только весь прикол в том, что компилятор компилит сишники по отдельности и инлайнить на этом этапе поздно. А линкер уже ничего сделать не может. Короче, 1 чувак сказал, что инлайн - только внутри модуля и поэтому описание инлайн-функции вместе с телом в порядке исключения разрешается помещать в h-файл, а не c-файл, чтобы компилятор мог ее подставить. Правильно?
WiseLord писал(а):И этот файл инклюдится сразу двумя c-файлами.
Походу...
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

aam писал(а):Короче, я так понял. Переменные я вс-таки должен объявлять ("unsigned char a;") именно в соответствующем сишнике (RC5.c). Тогда те из переменных, которые я хочу использовать другими модулями (файлами) проги, я должен дополнительно описать ("extern unsigned char a;") в h-файле. Те, которые сугубо личные и юзаются только внутри библиотеки - соответственно не описываю. Так?
Да вроде трое вам про это повторили :)
Вообще тоже практика нехорошая. Модуль не должен использовать (и светить наружу) никакие глобальные переменные. Правильнее делать функции, принимающие и возвращающие значения или указатели на всяческие структуры. А сами эти, структуры например, описаны в h-файле, объявлены в с-файле.
aam писал(а):Только весь прикол в том, что компилятор компилит сишники по отдельности и инлайнить на этом этапе поздно.
В смысле? Разговор был про то, что вы разбили одну большую функцию на несколько мелких. А если вы ещё их по разным файлам раскидали, то естественно никакой компилятор с линкером не разберётся.
Собутыльник Кота
Аватара пользователя
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев

Сообщение BCluster »

Модулем я считаю отдельный файл (.с) или группу таких файлов, если модуль сложный.
aam писал(а):Защита от двойного включения во всех h-файлах естественно написана.
А в описанной уважаемыми котами выше ситуации и нет двойного включения.
aam писал(а):Специально сделал поиск по всем файлам - запись вида "unsigned char a;" есть только в файле RC5.h
Вам выше описали как надо делать. Не определяйте вообще в .h переменные. Выше все было написано
Где-то в стандарте написано что-то типа такого: An external variable must be defined, exactly once, outside of any function; this sets aside storage for it. The variable must also be declared in each function that wants to access it; this states the type of the variable.
Грубо говоря. У тебя есть модуль module
в module.h написано
extern int blabla;
в module.c
int blabla;
то никакой гарантии что blabla будет виден из других модулей нет. В большинстве компиляторов виден. Но, например в IAR MSP430 это происходит через раз.
Но, если ты в файле другого модуля объявишь int blabla; - это будет та же самая переменная.
Но вообще, использование глобальных переменных (а особенно межмодульных) не приводит ни к чему хорошему, и то что вы увидели лишь вершина айсберга. Особенно если над проектом работает больше одного человека. Рекомендую использовать обёртки get/set для работы с ними. Ежели учесть, что в 80% случаев глобальные переменные менять не надо, то все сводится к get-функции.
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев

Сообщение BCluster »

Также рекомендую прочесть http://pragprog.com/book/jgade/test-dri ... embedded-c если англ позвоняет, причем не только уважаемому коту aam :)
Позволяет применять подходы ООП к embedded C, ну кроме основной темы TDD, которая тоже очень хороша :)
http://rutracker.org/forum/viewtopic.php?t=3546969 если ктот запиратить хочет )
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 13490
Зарегистрирован: Ср ноя 26, 2008 16:34:25
Откуда: Тамбовская обл.

Сообщение ploop »

BCluster писал(а):причем не только уважаемому коту aam
Спасибо, кстати. Тоже не мешает почитать, а то ООП расслабляет :)))
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Защита от двойного включения во всех h-файлах естественно написана.
Тут это не поможет.

Пример.

foo.h

Код: Выделить всё


...

uint8_t bar;

...

main.c

Код: Выделить всё


#include "foo.h"

void main(void)
{
  bar=1;

   ...
}
foo.c

Код: Выделить всё


#include "foo.h"

...

bar=0;

...
Такая конфигурация вызовет ошибку. Перед компиляцией содержимое foo.h будет подставлено и в main.c, и в foo.c. Сответственно, хотя поиск даст нам одно объявление bar, по факту для компилятора это будут два объявления одной и той же глобальной переменной в разных файлах, что, естесственно, есть ошибка. Ругнется либо компилятор, либо (что вероятнее), линкер (проверять лень).
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Ответить

Вернуться в «Разные вопросы по МК»