|
Си: 2 константы-структуры с полями-указателями друг на друга, как объяснить компилятору? |
|
|
|
Feb 29 2012, 23:22
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 13-08-11
Из: Воронеж
Пользователь №: 66 710

|
Собственно, сабжевая задача. Обходные варианты есть, но хочется красиво  Структура. Одно из полей - указатель на структуру этого же типа. 2 переменные. Одна содержит в этом поле указатель на вторую, вторая - на первую. Если не константы - то все работает, ибо мы присваиваем значение полям когда угодно. Если константы - не работает, ибо надо при определении заполнить её значениями, а вторая переменная получается ещё не определена и не получается на неё указать  ЗЫ сейчас пробую разнести на 2 файла и поиграться экстернами, но пока не получается  Вроде удалось добиться понимания от компилятора в результате следующих искусственных манипуляций: делается хедэр с определением типа Код 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}; Билд проекта собирается. ошибок не выдает. Теперь попозже проверю как это работает в реале
Сообщение отредактировал _Ivana - Feb 29 2012, 23:23
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 18)
|
Mar 1 2012, 05:54
|

Частый гость
 
Группа: Свой
Сообщений: 103
Регистрация: 17-05-09
Из: Ижевск
Пользователь №: 49 190

|
А если попробовать сделать члены структуры константами, а саму структуру переменной. Создать по объекту класса, а потом инициализировать констатнтый указатель (звучит как бред, однако Студия 2005 не ругнулась  ) Просто боюсь, что вылезут вилы при выполнений кода, по-скольку вы пытаетесь создать ссылку на еще не существующий объект...
--------------------
Шизоидный холерик
|
|
|
|
|
Mar 1 2012, 07:19
|

Частый гость
 
Группа: Свой
Сообщений: 103
Регистрация: 17-05-09
Из: Ижевск
Пользователь №: 49 190

|
Цитата(_Ivana @ Mar 1 2012, 11:46)  все поля константы а она сама не константа? В ОЗУ или флэш? А если половина полей константы? Не пробовал ещё так исхитряться  Да идея беспонтовая на самом деле)) А на счет куда поместит = WinAvr - помещает во флеш и копирует в ОЗУ, как и с любой переменной со спецификатором типа const. А для чего константный указатель?
Сообщение отредактировал Marto - Mar 1 2012, 07:24
--------------------
Шизоидный холерик
|
|
|
|
|
Mar 1 2012, 07:35
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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}; Объявление типа, при необходимости, можно вынести в заголовочный файл.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 1 2012, 09:19
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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) Еще вопросы?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 1 2012, 12:02
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 13-08-11
Из: Воронеж
Пользователь №: 66 710

|
Сергей Борщ блин, посыпАю голову пеплом! Стыдно  Просто эта задача и идея не моя, вчера (сегодня  ) в 3 ночи мне в аську написал товарищ и попросил помочь с этой задачкой - типа очень надо, код разбора-прыгания по структурам получается очень красивый, но вот с константами не работает - как он ни бился!  Он меня заверил, что он перепробовал в одном файле все варианты определений и задания начальных значений, в том числе и экстерны, но не смог решить "проблему курицы и яйца"! А поскольку он гораздо опытнее меня в программировании МК на Си, то я просто тупо поверил ему и решил исхитриться, но не удосужился проверить очевидное. Скопипастил ваш вариант в тестовый проект, все компилится и билдится без ошибок
|
|
|
|
|
Mar 1 2012, 15:38
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 13-08-11
Из: Воронеж
Пользователь №: 66 710

|
Казалось бы, все понятно и тема закрыта  Это так, но лично меня интересует ещё полтора нюанса: 0.5) в объявленииКод extern our_struct const s1; порядок указания типа и директивы "const" не имеет значения? Вроде проверил и так и так, работают оба варианта. 1) в том же объявлении у меня в варианте 2-х файлов вообще нет директивы "const". Проверил без этой директивы в варианте от Сергей Борщ - тоже работает. На такие мысли меня натолкнули Керриган с Риччи - написано, что объявление говорит о том, что переменная обладает определенными свойствами (в основном типом), а при определении выделяется для нее место в памяти. Если это так, тогда в объявлении можно не указывать "const", поскольку это относится к выделению места в памяти.
|
|
|
|
|
Mar 1 2012, 16:18
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 13-08-11
Из: Воронеж
Пользователь №: 66 710

|
Пока согласно моим заблуждениям, в объявлении это не означает ничего  А в определении - да, область размещения (ОЗУ или флэш). Про параметры функции - имхо они и так передаются по значению а не по ссылке и значит не меняются.
|
|
|
|
|
Mar 1 2012, 16:45
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(_Ivana @ Mar 1 2012, 20:18)  Пока согласно моим заблуждениям, в объявлении это не означает ничего а разве при объявлении мы не говорим, где расположится переменная? upd никогда не заморачивался, но проверил... const переменная должна определяться там же, где и объявляется
|
|
|
|
|
Mar 1 2012, 16:56
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 13-08-11
Из: Воронеж
Пользователь №: 66 710

|
Мне кажется что объявление - чистая надстройка Си, нужная компилятору только для того чтобы узнать какой тип у переменной. ЗЫ а я убрал "const" из объявления и никаких ошибок при компилировании/билде. Могу проверить в железе, но не скоро. Может ещё быть такое, что разные компиляторы по-разному на это дело реагируют, но мне мои заблуждения кажутся логичными и обоснованными
Сообщение отредактировал _Ivana - Mar 1 2012, 16:59
Эскизы прикрепленных изображений
|
|
|
|
|
Mar 1 2012, 17:05
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 13-08-11
Из: Воронеж
Пользователь №: 66 710

|
Цитата upd никогда не заморачивался, но проверил...
const переменная должна определяться там же, где и объявляется Не понял как вы это проверили. И почему тогда мой пример в самом первом посте не дает ошибок?
|
|
|
|
|
Mar 1 2012, 17:07
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(_Ivana @ Mar 1 2012, 20:56)  ЗЫ а я убрал "const" из объявления и никаких ошибок при компилировании/билде конечно! компилятор разместил их в ОЗУ Цитата(_Ivana @ Mar 1 2012, 21:05)  Не понял как вы это проверили то есть? оставил объявление константной переменной (во флеш), а попытался проинициализировать ее в main
|
|
|
|
|
Mar 1 2012, 17:57
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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 никакой магии не несет - он лишь заставляет компилятор проверять, не пытаетесь ли вы записать в такую переменную. То, что для некоторых процессоров такую переменную можно разместить во флешь и не копировать перед исполнением в ОЗУ, реализуется исключительно средствами линкера. Компилятор об этом совершенно ничего не знает.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|