Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Определение указателя
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
ISK2010
Использую Keil....

Есть переменная a. Теперь каким-то образом хочу указатель на int "b" не просто определить как адрес переменной "а", а используя некое константное выражение:

CODE
u32 a;

u32 *b = (u32*)(((u32)(&a) - 0x40000000)*32 + 0x42000000);


Но компилятор выдает ошибку типа "не константное выражение". Но я то знаю, что константное.

Что делать? Вариант проинициализировать этот указатель b перед использованием отпадает, т.к. он уже используется)

P.S. Это мне нужно для побитовых операций с некоторыми переменными в STM32F1xx.




GetSmart
Цитата
Что делать? Вариант проинициализировать этот указатель b перед использованием отпадает, т.к. он уже используется)

Непонятно, как уже используется?
xemul
Цитата(ISK2010 @ Sep 2 2011, 17:05) *
Но компилятор выдает ошибку типа "не константное выражение". Но я то знаю, что константное.

Вы можете на этапе компиляции сказать, по какому адресу живёт a? Вот и компилятор не может.
Цитата
Вариант проинициализировать этот указатель b перед использованием отпадает, т.к. он уже используется)

"П-п-прведи". (С)
Если что-то до такой степени мешает инициализировать b перед первым использованием, напишите свой init().
777777
Цитата(ISK2010 @ Sep 2 2011, 17:05) *
Есть переменная a. Теперь каким-то образом хочу указатель на int "b" не просто определить как адрес переменной "а", а используя некое константное выражение:
<...>

Ничченепонимаю. Ты можешь словами объяснить, куда должен указывать b?
ISK2010
Цитата(GetSmart @ Sep 2 2011, 17:38) *
Непонятно, как уже используется?
Я вас запутал. Имел в виду, что вариант этот уже используется.

Цитата(xemul @ Sep 2 2011, 17:47) *
Вы можете на этапе компиляции сказать, по какому адресу живёт a? Вот и компилятор не может.
Я не могу, а keil может. Например, определение: "u32 *b = (u32*)(((u32)(&a) - 0x40000000) + 0x42000000);" работает. А вот стоит добавить что-то сложнее вычитания или сложения, то ошибка.
Цитата(xemul @ Sep 2 2011, 17:47) *
"П-п-прведи". (С) Если что-то до такой степени мешает инициализировать b перед первым использованием, напишите свой init().
Я свой инит итак использую, но это не по феншую, и я думаю, что есть более хитрое решение.


Цитата(777777 @ Sep 2 2011, 18:19) *
Ничченепонимаю. Ты можешь словами объяснить, куда должен указывать b?
b должен указывать туда, куда мы определим с помощью мегаформулы из адреса &а. Если конкретно, то в моем случае b указывает на начало a в битбенд области ОЗУ.
sigmaN
Цитата
u32 *b = (u32*)(((u32)(&a) - 0x40000000)*32 + 0x42000000);

Мисье знает толк в извращениях )))

Вы может быть более конкретно бы описали суть решаемой Вами задачи? может быть окажется, что и не нужно всё это....
alexeyv
Цитата
А вот стоит добавить что-то сложнее вычитания или сложения, то ошибка.


Почитайте стандарт (или любую книжку по Си).
С указазателями можно выполнять ТОЛЬКО следущие операции:
  • & - взятие адреса
  • * - взятие значения
  • присвоение указателей
  • сложение/вычитание указателя и целого числа
  • сравнение указателей
  • присвоение нуля и сравнение с ним
  • Может что еще забыл!?!?


И ВСЕ!!!!
В этом списке нету ни умножения, ни деления, ни даже возведения в степень.
А теперь посмотрите на свой код и скажите какая операция лишняя??
GetSmart
В рунтайме любые операции работают. На этапе компиляции ограниченное кол-во.
Палыч
Цитата(GetSmart @ Sep 3 2011, 09:48) *
В рунтайме любые операции работают. На этапе компиляции ограниченное кол-во.

Какие операции "не работают" на этапе компиляции в примере ТС ? Я понимаю, что значение адреса переменной на этапе компиляции неизвестно, будет определено позже линковщиком, а в примере ТС значение этого адреса на что-то там умножается... В общем, я бы с Вами согласился, о том, что не все операции "работают" при компиляции, но (!) давайте упростим пример ТС до такого
Код
u32 * b = (u32 *)( (u32)(&a) );
Что мы видим? Компилятор считает это неконстантным выражением. Пробуем найти: какая часть этого выражения - "не константа" с точки зрения компилятора?
Код
u32   c = (u32)(&a);
Здесь всё нормально. Выходит, что преобразование u32 в указатель делает выражение неконстантным? Пробуем:
Код
u32 * d= (u32 *)( 0x200UL );
Тоже - всё нормально. Так почему же не "работает" u32 * b = (u32 *)( (u32)(&a) ) ? Кто может объяснить?

P.S. А, таким образом извращатся с адресами я бы ТС не рекомендавал - нужно искать друкое решение Вашей залачи.
ISK2010
Цитата(Палыч @ Sep 3 2011, 11:05) *
Какие операции "не работают" на этапе компиляции в примере ТС ? Я понимаю, что значение адреса переменной на этапе компиляции неизвестно, будет определено позже линковщиком, а в примере ТС значение этого адреса на что-то там умножается... В общем, я бы с Вами согласился, о том, что не все операции "работают" при компиляции, но (!) давайте упростим пример ТС до такого
Код
u32 * b = (u32 *)( (u32)(&a) );
Что мы видим? Компилятор считает это неконстантным выражением. Пробуем найти: какая часть этого выражения - "не константа" с точки зрения компилятора?


Не работает умножение 32. А пример u32 * b = (u32 *)( (u32)(&a) ); работает в keil.


С помощью этой формулы я получаю адрес начала структуры флагов в битбенд области ОЗУ. И обращаюсь к каждому флагу в отдельности. На данный момент это очень оказалось кстати. Например, раньше я работал с флагами через маски или флаги делал 8битными. И к этом флагам добавлял флаги "занятости флагов", дабы не произошло ошибок чтения-модификации-записи. А с битбендом отказался от всего этого. Никаких масок и проблем.

Сейчас адрес начала флагов в битбенд области ОЗУ расчитываю в функции инициализации флагов. и к любому флагу обращаюсь так:
Код
*(u32*)((u32)Addr_BB_Flags + NumberOfFlag<<2) = 1; //установка флага
*(u32*)((u32)Addr_BB_Flags + NumberOfFlag<<2) = 0; //сброс
и все замечательно работает.

Думал, что есть какая-нибудь фишка keil, так сказать какой-нибудь атрибут или прагма, чтобы можно было без всякой инициализации определить этот указатель
alexeyv
Код
Тоже - всё нормально. Так почему же не "работает" u32 * b = (u32 *)( (u32)(&a) ) ? Кто может объяснить?


У меня все работает. Компилируется без ошибок. Правда не в Keil.
И синтаксически это правильное выражение.

Для ТС.
Уберите умножение из выражения работы с указателями. Ни один компилятор не должен поддерживать операцию умножения с указателями.

ISK2010
Нашел еще одно решение) Тупо заставил запихнуть мои флаги по конкретному адресу ОЗУ 0x20004000 и на калькуляторе рассчитал адрес зеркала в бидбенд области = 0x220C8000. Но это опять не по феншую
alexeyv
У вас в начале топика в корне не правильная формула расчета

д.б. примерно так:
Код
// в  начале файла, если этипеременные глобальные:
u32 a;
u32 *b;

// в теле какой-либо функции, перед использованием b:
b = (u32 *)( 0x22000000 + ((u32)(&a)- 0x20000000)*32);


Дело в том что на этапе компиляции, еще не известны все адреса и компилятор не может вычислить такое сложное выражение
Но в теле какой-либо функции можно схитрить, вычислив адрес как простое арифметическое выражение и преобразовать его в адрес.

Если же вы хотите задать значение "b" на этапе компиляции, то возможно вам надо расположить "a" по строго определенному адресу. Для этого изучайте директивы линковщика и компилятора.

Цитата
A mapping formula shows how to reference each word in the alias region to a corresponding
bit in the bit-band region. The mapping formula is:
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)
where:
bit_word_addr is the address of the word in the alias memory region that maps to the
targeted bit.
bit_band_base is the starting address of the alias region
byte_offset is the number of the byte in the bit-band region that contains the targeted bit
bit_number is the bit position (0-7) of the targeted bit.
Example:
The following example shows how to map bit 2 of the byte located at SRAM address
0x20000300 in the alias region:
0x22006008 = 0x22000000 + (0x300*32) + (2*4).
Writing to address 0x22006008 has the same effect as a read-modify-write operation on bit
2 of the byte at SRAM address 0x20000300.
Reading address 0x22006008 returns the value (0x01 or 0x00) of bit 2 of the byte at SRAM
address 0x20000300 (0x01: bit set; 0x00: bit reset).
skripach
Цитата
А пример u32 * b = (u32 *)( (u32)(&a) ); работает в keil.

Я бы на месте компилятора такое глотать не стал sm.gif, хотя в IAR тоже работает, вернее компилится, а работает или нет не проверял.
ReAl
Цитата(alexeyv @ Sep 3 2011, 12:34) *
Дело в том что на этапе компиляции, еще не известны все адреса и компилятор не может вычислить такое сложное выражение
Это, вообще говоря, не компиляторово дело, а линкерово. Компилятор и &a может только записать как «а туда затолкай адрес вон того» (особенно при extern u32 a).
Если линкер не позволяет задать ему сложные выражения (из известных на этапе линковки величин!), то ничего и не выйдет.

Цитата(alexeyv @ Sep 3 2011, 12:34) *
Но в теле какой-либо функции можно схитрить, вычислив адрес как простое арифметическое выражение и преобразовать его в адрес.
В режиме С++ катит и строка из корневого сообщения -- компилятор просто создаст функцию-инициализатор для b и затолкает её в таблицы на правах конструктора.
Палыч
Цитата(ISK2010 @ Sep 3 2011, 12:15) *
пример u32 * b = (u32 *)( (u32)(&a) ); работает в keil.

Цитата(alexeyv @ Sep 3 2011, 12:28) *
У меня все работает. Компилируется без ошибок. Правда не в Keil. И синтаксически это правильное выражение.

Ах, вон оно что! В Keil... А, я то - попробовал в IAR для AVR... И, кстати, - не работает и в таком, упращенном примере.
skripach
Цитата
А, я то - попробовал в IAR для AVR... И, кстати, - не работает и в таком, упращенном примере.

ARMовый 6-й IAR компили-т без умножения...
sigmaN
Все тут пишут, что умножение указателей не поддерживается... оно то, конечно, верно, но ведь ТС пытается сначала привести адрес к u32, потом выполнить все действия и привести результат к указателю.
Ситуация с константностью выражения более-менее понятна, но вот где тут операции с указателями? Мне пока не ясно.

P.S. придерживаюсь мнения, что ТС должен пректатить все эти извращения и найти более православный способ сделать то, что он хочет.
toweroff
Цитата(sigmaN @ Sep 3 2011, 23:59) *
Мне пока не ясно.

вот все и пытаются понять, как оно там компилятором поймется и линкером сложится sm.gif
sigmaN
Ааа, ну да! Вообще-то логично, что считать должен уже линкер, который знает адрес. И он не обязан уметь делить и умножать. Согласен.
toweroff
Цитата(sigmaN @ Sep 4 2011, 00:13) *
И он не обязан уметь делить и умножать

не только к Вам, а к общественности - а ведь действительно, линкер ТОЛЬКО собирает?
ни разу не приходилось разбирать obj файлы, линкер собирает из них только то, что уже явно указано в размещении, без каких-либо вычислений?
Палыч
Цитата(toweroff @ Sep 4 2011, 00:20) *
без каких-либо вычислений?
Конечно же - вычисляет. Вычисления, само-сабой, без наворотов.
toweroff
Цитата(Палыч @ Sep 4 2011, 00:32) *
Конечно же - вычисляет. Вычисления, само-сабой, без наворотов.

я и говорю - относительные размещения
не вычисляет же выражения... компилятору - компиляторово
sigmaN
Хехе, а интересный же вопрос, а! Особенно вариант как у ТС, когда указатель преобразовывается в int и пошло-поехало...
И, судя по отзывам, разные компиляторы по разному ведут себя.. А как правильно?
Ну и интереснее всего тут именно роль линкера.
skripach
Цитата
А как правильно?

Сейчас подойдет товарищ из Риги и всем всё объяснит. biggrin.gif
toweroff
Цитата(skripach @ Sep 4 2011, 04:28) *
Сейчас подойдет товарищ из Риги и всем всё объяснит. biggrin.gif

он мне тоже из ответов задолжал немного biggrin.gif, если, конечно, будет желание
Но, такое ощущение, что он ловит омаров/раков/креветок или что там в отпуске делают.. sm.gif

UPD

Хорош прикалываться. Не дай Бог чего bb-offtopic.gif
sigmaN
Цитата
Сейчас подойдет товарищ из Риги и всем всё объяснит.
Да. Я тоже о нём подумал)))))
ISK2010
А что в выражении u32 * b = (u32 *)( (u32)(&a) ) вы считаете извращением? Я таким уже давно пользуюсь и успешно.
Насчет неправильной формулы - это я случайно когда писал тут вставил адрес периферии, для которой, кстати, я также через битбенд флаги всякие юзаю.




Сейчас временно сделал во так:
Код
MB_ByteCoils MB_Coils[MB_QtyBytesCoils]__attribute__((at(0x2004000))); // массив структур флагов
  
  u32 MB_Addr_BB_Coils = 0x220C8000; // численно адрес зеркала
  
  
  
  /*А использую так:*/
  
<p>   *(u32*)(MB_Addr_BB_Coils + NumberOfFlag*4) = 1;
Ну и соответственно на асме это выглядит так:

Код
0x08001AB2 6812      LDR      r2,[r2,#0x00]

0x08001AB4 F04F0101  MOV      r1,#0x01

0x08001AB8 F8421020  STR      r1,[r2,r0,LSL #2]
Куда меньше чем при использовании масок и т.п.
sigmaN
Лично я всегда думал, что изобилие в коде приведений к типу - есть признак не совсем корректного использования возможностей языка...
Нет сомнений в том, что это работает, однако же не исключено, что смена дизайна позволит существенно упростить какие-то вещи.
Мне сложно предложить что-то конкретное, т.к. я не вижу картину целиком, но мне точно не очень нравится видеть такое
Код
*(u32*)(MB_Addr_BB_Coils + NumberOfFlag*4) = 1;
Ну точно же можно заставить компилятор всё это сделать автоматически. Например, если у вас в массиве структуры с полем флаг, то почему бы не писать
Код
MB_Coils[номер структуры].флаг = 1;
строкой выше вычислить номер структуры, если требуется получить её из общего номера флага, например..
Это всего-лишь догадка, т.к. я пока не совсем понял, что конкретно должен сделать Ваш код. Просто идея в том, чтобы использовать возможности языка, а не просто манипулировать указателями, на всю катушку пользуясь тем, что язык и это позволяет.
Как-то так, в общем ))

P.S. Очень жаль, что не удастся следить за дискуссией дальше sad.gif Ближайшие пару дней буду трястись в поезде....
ISK2010
Читаете что я пишу? Всякие там вычисления номера структуры и номера флага в ней раньше как-раз и использовались. А используя битбендинг все превратилось в одну строку на С. При этом использую макрос #define MB_FLAG_SET(a) (*(u32*)(MB_Addr_BB_Coils + a*4) = 1). Ну и что тут не нравится? Зря вы так боитесь приведения типов. Язык не то что "позволяет", а обязан такое позволять. Я к примеру ненавижу использовать union.
ViKo
Можно использовать макроопределение такого вида (и пример применения):
Код
#define ALIAS_PTR(VarPtr, BitNum) \
  *((__IO uint32_t *) (((uint32_t) &(VarPtr) & 0xf0000000) | 0x02000000 \
  + (((uint32_t) &(VarPtr) & 0xfffff)<<5) | (BitNum<<2)))

  ALIAS_PTR(GPIOC->ODR, 8) = ~ALIAS_PTR(GPIOC->ODR, 8);

Но лучше задать атрибут для структуры из битовых полей, и Keil сам будет обращаться к битам через bit-band
Код
typedef struct {
  int  HelpEna : 1;
  int  Lang : 2;
  int  Vect : 1;
  int  Wide : 1;
  int  Scale : 2;
  int  dummy : 1;
} DPY_t __attribute__((bitband));


ISK2010
Да, у меня уже используется что-то подобное :
CODE
typedef union
{
u8 Byte;
struct
{
u8 B0:1;
u8 B1:1;
u8 B2:1;
u8 B3:1;
u8 B4:1;
u8 B5:1;
u8 B6:1;
u8 B7:1;
}Bit __attribute__((bitband));
} MB_ByteCoils;
А тут понадобилось обращаться к флагам именно по номеру . Еще в марте modbus поднял, тут в пятницу за час до момента Х решил ченить соптимизировать)
ViKo, я писал умножение на 32 и сдвиг на 5. Одинаково выходит, оптимизирует как надо.
XVR
Цитата(toweroff @ Sep 4 2011, 00:20) *
не только к Вам, а к общественности - а ведь действительно, линкер ТОЛЬКО собирает?
Формат ELF (не знаю, что там используется в IAR и Keil, но подозреваю, что именно он) поддерживает весьма ограниченные операции над адресами (на link time) - только адрес +/- константа. Никакой другой арифметики не поддерживается

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.