Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Си: 2 константы-структуры с полями-указателями друг на друга
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
_Ivana
Собственно, сабжевая задача. Обходные варианты есть, но хочется красиво sm.gif
Структура. Одно из полей - указатель на структуру этого же типа.
2 переменные. Одна содержит в этом поле указатель на вторую, вторая - на первую. Если не константы - то все работает, ибо мы присваиваем значение полям когда угодно.
Если константы - не работает, ибо надо при определении заполнить её значениями, а вторая переменная получается ещё не определена и не получается на неё указать sm.gif

ЗЫ сейчас пробую разнести на 2 файла и поиграться экстернами, но пока не получается sm.gif

Вроде удалось добиться понимания от компилятора в результате следующих искусственных манипуляций:

делается хедэр с определением типа
Код
typedef struct our
{
    unsigned char c;
    struct our *s_our;
} our_struct;


делается 2 файла, в которые инклюдится этот хедэр и пишется в одном
Код
extern our_struct s1;
const our_struct s2 = {'A', &s1};


и в другом
Код
extern our_struct s2;
const our_struct s1 = {'A', &s2};


Билд проекта собирается. ошибок не выдает. Теперь попозже проверю как это работает в реале sm.gif
Marto
А если попробовать сделать члены структуры константами, а саму структуру переменной.
Создать по объекту класса, а потом инициализировать констатнтый указатель blink.gif
(звучит как бред, однако Студия 2005 не ругнулась blink.gif )

Просто боюсь, что вылезут вилы при выполнений кода, по-скольку вы пытаетесь создать ссылку на еще не существующий объект...
_Ivana
Спасибо за идею, вечером попробую. Только всвязи с этим возникают вопросы: куда компилятор поместит структуру у в которой все поля константы а она сама не константа? В ОЗУ или флэш? А если половина полей константы? Не пробовал ещё так исхитряться sm.gif

А адреса всех объектов в памяти (и ОЗУ и флеш), как мне подсказал один товарищ, определяются только на этапе линковки, когда все файлы проекта откомпилированы. Поэтому оба объекта уже вроде как существуют "в уме" компилятора. А если пытаться сделать в одном файле - до линковки даже не доходит, ошибка и ругань возникает сразу на этапе компиляции - ибо компилятор справедливо "не видит" еще не определенную переменную при последовательном анализе кода. Кстати, использование экстернов в одном файле не помогает компилятору увидеть ниже определенную переменную. Хотя согласен, что есть некие опасения насчет того, как это будет работать sm.gif
Marto
Цитата(_Ivana @ Mar 1 2012, 11:46) *
все поля константы а она сама не константа? В ОЗУ или флэш? А если половина полей константы? Не пробовал ещё так исхитряться sm.gif


Да идея беспонтовая на самом деле))
А на счет куда поместит = WinAvr - помещает во флеш и копирует в ОЗУ, как и с любой переменной со спецификатором типа const.

А для чего константный указатель?
Сергей Борщ
QUOTE (_Ivana @ Mar 1 2012, 01:22) *
делается 2 файла, в которые инклюдится этот хедэр и пишется в одном
Можно то же самое сделать и в одном файле

CODE
typedef struct our
{
    unsigned char c;
    struct our const *s_our;
} our_struct;

extern our_struct const s1;
const our_struct s2 = {'A', &s1};
const our_struct s1 = {'A', &s2};
Объявление типа, при необходимости, можно вынести в заголовочный файл.
Marto
Сами пробовали компилить?
Сергей Борщ
QUOTE (Marto @ Mar 1 2012, 11:01) *
Сами пробовали компилить?
Да.
CODE
D:\Projects\test\uuu>make
avr-gcc --version
avr-gcc.exe (WinAVR 20100110) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

cat test.c
typedef struct our
{
    unsigned char c;
    struct our const *s_our;
} our_struct;

extern our_struct const s1;
const our_struct s2 = {'A', &s1};
const our_struct s1 = {'A', &s2};

int main()
{
    for(;;)
       ;
}
Compiling: test.c
avr-gcc  -mmcu=atmega8 -Wall -gdwarf-2  -DF_CPU=14745000UL  -Os  -fsigned-char -funsigned-bitfields -fshort-enums -MD -MP -MT ./release/obj/test.o -MF ./release/dep/test.o.d  -ffunction-sections  -fdata-sections -fno-ivopts --param inline-call-cost=0 -fno-move-loop-invariants -Wa,-ahlmsd=./release/lst/test.lst -c  test.c -o release/obj/test.o
Linking: release/struct_test.elf
avr-gcc -mmcu=atmega8 -Wl,-Map=./release/lst/struct_test.map -Wl,--gc-sections -Wl,--relax  ./release/obj/test.o    -o release/struct_test.elf
Generating hex: release/struct_test.hex
avr-objcopy -O ihex -R .eeprom  release/struct_test.elf release/struct_test.hex
Generating eep: release/struct_test.ee.hex
avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings release/struct_test.elf release/struct_test.ee.hex || exit 0
Generating disassembly: release/lst/struct_test.lss
avr-objdump -h -S release/struct_test.elf > release/lst/struct_test.lss
AVR Memory Usage
----------------
Device: atmega8

Program:      84 bytes (1.0% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)
Еще вопросы?
Marto
Вопросов нет. Нашел ошибку у себя. Спасибо.
_Ivana
Сергей Борщ блин, посыпАю голову пеплом! Стыдно sm.gif Просто эта задача и идея не моя, вчера (сегодня sm.gif) в 3 ночи мне в аську написал товарищ и попросил помочь с этой задачкой - типа очень надо, код разбора-прыгания по структурам получается очень красивый, но вот с константами не работает - как он ни бился! sm.gif Он меня заверил, что он перепробовал в одном файле все варианты определений и задания начальных значений, в том числе и экстерны, но не смог решить "проблему курицы и яйца"! А поскольку он гораздо опытнее меня в программировании МК на Си, то я просто тупо поверил ему и решил исхитриться, но не удосужился проверить очевидное.
Скопипастил ваш вариант в тестовый проект, все компилится и билдится без ошибок sm.gif
_Ivana
Казалось бы, все понятно и тема закрыта sm.gif Это так, но лично меня интересует ещё полтора нюанса:

0.5) в объявлении
Код
extern our_struct const s1;

порядок указания типа и директивы "const" не имеет значения? Вроде проверил и так и так, работают оба варианта.

1) в том же объявлении у меня в варианте 2-х файлов вообще нет директивы "const". Проверил без этой директивы в варианте от Сергей Борщ - тоже работает.

На такие мысли меня натолкнули Керриган с Риччи - написано, что объявление говорит о том, что переменная обладает определенными свойствами (в основном типом), а при определении выделяется для нее место в памяти. Если это так, тогда в объявлении можно не указывать "const", поскольку это относится к выделению места в памяти.
toweroff
Цитата(_Ivana @ Mar 1 2012, 19:38) *
Если это так, тогда в объявлении можно не указывать "const", поскольку это относится к выделению места в памяти.

в объявлении это, скорее всего, означает только то, что переменная разместится в неизменяемой области (например, flash/ROM)
при указании const в параметрах функции - то, что переменная гарантированно не будет изменена в этой функции
_Ivana
Пока согласно моим заблуждениям, в объявлении это не означает ничего sm.gif А в определении - да, область размещения (ОЗУ или флэш).
Про параметры функции - имхо они и так передаются по значению а не по ссылке и значит не меняются.
toweroff
Цитата(_Ivana @ Mar 1 2012, 20:18) *
Пока согласно моим заблуждениям, в объявлении это не означает ничего

а разве при объявлении мы не говорим, где расположится переменная?

upd
никогда не заморачивался, но проверил...

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

ЗЫ а я убрал "const" из объявления и никаких ошибок при компилировании/билде. Могу проверить в железе, но не скоро. Может ещё быть такое, что разные компиляторы по-разному на это дело реагируют, но мне мои заблуждения кажутся логичными и обоснованными sm.gif
toweroff
Вопрос. Мы говорим о расширении языка для MC?
_Ivana
Цитата
upd
никогда не заморачивался, но проверил...

const переменная должна определяться там же, где и объявляется

Не понял как вы это проверили. И почему тогда мой пример в самом первом посте не дает ошибок?
toweroff
Цитата(_Ivana @ Mar 1 2012, 20:56) *
ЗЫ а я убрал "const" из объявления и никаких ошибок при компилировании/билде

конечно!
компилятор разместил их в ОЗУ

Цитата(_Ivana @ Mar 1 2012, 21:05) *
Не понял как вы это проверили

то есть?
оставил объявление константной переменной (во флеш), а попытался проинициализировать ее в main
Сергей Борщ
QUOTE (_Ivana @ Mar 1 2012, 17:38) *
0.5) в объявлении
CODE
extern our_struct const s1;

порядок указания типа и директивы "const" не имеет значения? Вроде проверил и так и так, работают оба варианта.
Да, не имеют.
Однако обратите внимание, что char const * Variable; char * const Variable; и char const * const Variable; - три объявления совершенно разных указателей. Аналогично с квалификатором volatile и квалификаторами адресных пространств (если они имеются в качестве расширения языка) наподобие __flash, __eeprom.
QUOTE (_Ivana @ Mar 1 2012, 17:38) *
1) в том же объявлении у меня в варианте 2-х файлов вообще нет директивы "const". Проверил без этой директивы в варианте от Сергей Борщ - тоже работает.

Если у вас нет const ни в строке extern our_struct s1; ни в строке const our_struct s1 = {'A', &s2}; - тоже все нормально. Если только в первой - по идее должна быть ошибка. Ведь вы обманули компилятор - вы сказали, что в s1 можно писать, а потом объявили ее константной. Опять же, если вы уберете const у struct our const *s_our; - вы не сможете присвоить этому полю адрес константной s2 или s1. Похоже именно на это и наткнулся ваш товарищ. В Си существует правило неявного приведения типов - указателю на константную переменную можно присвоить адрес неконстантного объекта (этим вы лишь ограничиваете операции доступа к такой переменной операциями чтения), но указателю на неконстантную переменную нельзя присвоить адрес константной переменной - тем самым вы разрешали бы через этот указатель операции записи в константную переменную, а это уже жульничество, для него существуют явные приведения типа, которые надо использовать тогда и лишь только тогда, когда такое жульничество необходимо и осознанно.

QUOTE (_Ivana @ Mar 1 2012, 17:38) *
На такие мысли меня натолкнули Керриган с Риччи - написано, что объявление говорит о том, что переменная обладает определенными свойствами (в основном типом),
Да, совершенно верно. И свойство"нельзя писать" - такое же неотъемлемое, как и размер, тип или знаковость. Ведь компилятор должен на основе этого объявления проверять ваши обращения к этой переменной и использовать (где необходимо) правиля неявного приведения типов.

QUOTE (_Ivana @ Mar 1 2012, 17:38) *
а при определении выделяется для нее место в памяти. Если это так, тогда в объявлении можно не указывать "const", поскольку это относится к выделению места в памяти.
Вы глубоко ошибаетесь. В вашей писюге все программы, включая константы и исполняемый код, целиком размещаются в ОЗУ. И const на это повлиять не может при всем желании. Сам по себе квалификатор const никакой магии не несет - он лишь заставляет компилятор проверять, не пытаетесь ли вы записать в такую переменную. То, что для некоторых процессоров такую переменную можно разместить во флешь и не копировать перед исполнением в ОЗУ, реализуется исключительно средствами линкера. Компилятор об этом совершенно ничего не знает.
_Ivana
Сергей Борщ очередное спасибо за грамотное и детальное объяснение (возможно для многих давно очевидных) вещей! И сорри за глупые вопросы - просто хочется сформировать в голове четкое представление-абстракцию: как же это все на самом деле работает sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.