|
Снова про const, не получается переползти с С на СРР |
|
|
|
Jan 10 2011, 06:05
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Искал свою проблему в форуме, но не нашел решения. Проблема в следующем. Имеется готовый проект на С для IAR-430A, кристаллы ARM ST91х. Использую структуры, состоящие из данных-констант вида: Код typedef struct{ const Tsome_type some_data1; const Tsome_type some_data2; // ...etc } Tsome_info; Затем в коде на С создаю эти структуры с уже конкретными константами в полях Код const Tsome_info info1={,,,,,}; const Tsome_info info2={,,,,,}; const Tsome_info info3={,,,,,}; //..etc На С все прекрасно живет, компилятор помещает мои структуры в сегмент CONST, а линкер- в ROM. Но, тот же самый код на СPP приводит к размещению структур в сегменте CSTACK вместе с другими объектами. В результате куча констант хранится в RAM, которой и так мало! Я в шоке.  Можно ли как-то победить эту проблему? Или придется перелопачивать идеологию проекта?
|
|
|
|
|
 |
Ответов
(1 - 45)
|
Jan 10 2011, 06:41
|

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

|
QUOTE (Aprox @ Jan 10 2011, 11:05)  На С все прекрасно живет, компилятор помещает мои структуры в сегмент CONST, а линкер- в ROM. Но, тот же самый код на СPP приводит к размещению структур в сегменте CSTACK вместе с другими объектами. Странно это. Разница между C и C++ в плане const лишь в том, что в C++ константы по-умолчанию имеют локальную область видимости, что соответствует static const в C. Чтобы получить константы с глобальной областью видимости, их надо определять через extern const type = value; Но это никак не связано с размещением на стеке. Приведите побольше кода, попробуем разобраться.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 10 2011, 06:46
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Ну и оставьте свои Код const Tsome_info info1={,,,,,}; ... в С-ом модуле, а в .h файле объявите их как Код #ifdef __cplusplus
extern "C" const Tsome_info info1;
#else
extern const Tsome_info info1;
#endif
|
|
|
|
|
Jan 10 2011, 08:58
|

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

|
QUOTE (Aprox @ Jan 10 2011, 12:55)  Чисто на CPP создавать структуры из данных-констант в ROM видимо не получится. В руководстве прочитал, что объекты и структуры компилятор СРР IAR размещает в сегмент CSTACK, который затем в RAM. Уже несколько лет пользуюсь ИАРом 4.30, пишу на C++, и он все константы прекрасно располагает во флеше: CODE 9 struct my_type 10 { 11 int a; 12 int b; 13 }; 14
\ In segment DATA_C, align 4, align-sorted 15 extern my_type const aa = {1,2}; \ aa: \ 00000000 010000000200 DC32 1, 2 \ 0000
\ In segment DATA_C, align 4, align-sorted 16 extern my_type const bb = {3,4}; \ bb: \ 00000000 030000000400 DC32 3, 4 \ 0000 А вы эти константы случайно не внутри функции без static объявляете?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 10 2011, 16:44
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(sergeeff @ Jan 10 2011, 14:05)  В общем случае надо явно компилятору/линкеру сообщить, какие данные в каком именно сегменте вы хотите расположить, а не просто использовать размещение по умолчанию. Синтаксис таких команд сильно зависит от применяемой связки компилятор/линкер. Почитайте документацию, это не очень сложно. Понимаете, я хотел получить упрощение написания программ за счет перехода на обьектное программирование, а получается, надо разбираться в куче дополнительных подробностей, которые сводят на нет преимущества СРР. Понятно, что директивами pragma можно рулить сегментами. Но зачем эти сложности и лишний раз тыкать в клавиатуру? В кодах на "С" все нужное происходит автоматом. Кроме того, я четко видел в мануале- объекты и структуры помещаются в один сегмент данных. И тут, наверное, уже никакими ухищрениями их не разъединить. Цитата(Сергей Борщ @ Jan 10 2011, 14:58)  Уже несколько лет пользуюсь ИАРом 4.30, пишу на C++, и он все константы прекрасно располагает во флеше: Вот мой участок кода, который структуру из констант размещает в RAM. Тестовая программа в файле с расширением .cpp, т.е. будет работать СРР компилятор. Код #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdbool.h>
typedef struct{ const char* row[2]; } TFormInfo;
int main() { const TFormInfo form_info ={ "row1", "row2" };
return 0; } Пробежав симулятором от main до return, открываем структуру в QuickWatch и видим- она размещена в RAM.
|
|
|
|
|
Jan 10 2011, 16:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Вы должны четко понять, что С и С++ это разные компиляторы. Сам С++ существенно строже работает с разными типами данных и это сделано для повышения надежности и безопасности генерируемого кода. В приведенном вами примере структура будет располагаться в стеке, так как объявлена внутри функции, соответственно в RAM. Коллега Борщ советовал вам ее объявить как: Код static const TFormInfo form_info ={ "row1", "row2" }; Попробуйте! Да, и кто вам сказал, что программа на С++ будет проще, чем на С? Там своих заморочек будет предостаточно, особенно на этапе его освоения.
|
|
|
|
|
Jan 11 2011, 18:52
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Aprox @ Jan 12 2011, 00:04)  как в Embedded С++ сделать так, чтобы свойства-константы оказались в ROM, а конструктор TComboBox выглядел бы прилично? Ну вы всё правильно делаете - константные структуры, и указатель на них в качестве параметра конструктора. Если объектов немного, то можно шаблонами. Типа Код struct ComboProps1 { enum { width = 200 }; enum { height = 500 }; enum { some_bool_prop1 = false }; ... };
struct ComboProps2 { enum { width = 300 }; enum { height = 200 }; enum { some_bool_prop1 = true }; ... };
template<typename Props> class TComboBox { enum { width = Props::width }; ... }
TComboBox<ComboProps1> Combo1; TComboBox<ComboProps2> Combo2;
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jan 12 2011, 05:12
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Oldring @ Jan 11 2011, 18:25)  В голых сях - иначе. Было у Страуструпа эссе по этому поводу. Слово гарантирует, что программист не модифицирует объект неумышленно. Но всё равно если есть конструктор-деструктор, они будут вызваны. Ни конструктор, ни деструктор не изменяют константных членов-данных. Только создают или удаляют. То, что это не очень вяжется с концепциями реализации ПЗУ - так ПЗУ и константы - это разные вещи. В конструкторе допускается инициализация константных полей, но только в списке инициализации, в теле конструктора уже нет. И работает это только для целых (почему такое ограничение, не знаю). Т.ч. ничего там не меняется. Цитата(Oldring @ Jan 11 2011, 18:25)  И иногда константные объекты мутируют. Было даже введено в язык специальное ключевое слово "mutable". Но иногда обходятся по-старинке и без него, снимая константность с указателя. mutable - это из другой песни. Это нужно, чтобы можно было отдельные поля модифицировать в фукнциях-членах, объявленных как const. Заметьте, что речь идет не о константных членах-данных. Такие данные изменить не получится в любом случае.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jan 12 2011, 17:23
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
const_cast<> цяця-ляля, но до тех пор, пока мы снимаем то, что оделось по дроге - метка (*1) ниже. А когда оно изначально было const -- метка (*2) -- имеем в полный рост UB, что как раз в embedded с флешами всякими и вылезет. На PC шара прокатывает. Пока не начали секции с константами селить в страницы "только для чтения" с исключениями "генерал Фаульта" при попытке записи. C++2003 7.1.5.1 The cv-qualifiers ... 4 Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior. 5 [Example: Код const int ci = 3; // cv-qualified (initialized as required) ci = 4; // ill-formed: attempt to modify const int i = 2; // not cv-qualified const int* cip; // pointer to const int cip = &i; // OK: cv-qualified access path to unqualified *cip = 4; // ill-formed: attempt to modify through ptr to const int* ip; // cast needed to convert const int* to int* ip = const_cast<int*>(cip); // defined: *ip points to i, a non-const object (*1) *ip = 4; const int* ciq = new const int (3); // initialized as required int* iq = const_cast<int*>(ciq); // cast required *iq = 4; // undefined: modifies a const object (*2)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jan 13 2011, 02:47
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(jorikdima @ Jan 12 2011, 18:34)  const_cast<>() ? После const_cast<> компилятор "умывает руки" и никакой защиты и проверок со его стороны стороны нет. Речь шла о безопасных преобразованиях (для чего умышленно вводят const в объявления) по правилам языка - так вот они не допускают модификации константных объектов. Цитата(Oldring @ Jan 12 2011, 14:29)  После явного снятия константности - легко. Ага. А еще метод: const int a = 10; int addr = (int)&a; int *p = (int*)addr; (*p)++; И еще много таких финтов можно придумать. Только речь о конструкциях языка, а не о хаках
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jan 13 2011, 06:05
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(AHTOXA @ Jan 12 2011, 00:52)  Ну вы всё правильно делаете - константные структуры, и указатель на них в качестве параметра конструктора. Ваш вариант задания констант-описаний выглядит читабельно и красиво. Однако, если в структуре-описания много разных типов, например, строки, указатели на места памяти, float и пр., то ваш вариант приводит к излишней писанине в момент декларации самих констант. Мне кажется, следующий вариант экономней в смысле писанины Код typedef struct{ int i; float f; char* s; } Tprops;
//----здесь декларации свойств с экономией писанины static const Tprops prop1 ={13, 3.14, "Name1"}; // это точно попадает в ROM static const Tprops prop2 ={16, 2.73, "Name2"}; // это точно попадает в ROM
class Tobj {//------------- const Tprops* p; public: Tobj(){} Tobj(const Tprops* prop) {p=prop;} // здесь можно пользоваться элементами описания *p.f или p->i };
Tobj example1=&prop1; Tobj example2=&prop2;
...
|
|
|
|
|
Jan 13 2011, 06:29
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Aprox @ Jan 13 2011, 14:05)  Мне кажется, следующий вариант экономней в смысле писанины Дык, моя фраза Цитата(AHTOXA @ Jan 12 2011, 02:52)  константные структуры, и указатель на них в качестве параметра конструктора. была как раз про этот вариант  А с шаблонами - это альтернативный.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jan 13 2011, 06:54
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(ReAl @ Jan 12 2011, 23:23)  А когда оно изначально было const -- метка (*2) -- имеем в полный рост UB, что как раз в embedded с флешами всякими и вылезет. Вы же не считаете, что запихивание констант во флеш - это defined bihavior? Всё, что обсуждается в этой теме, и есть UB. Цитата(Aprox @ Jan 13 2011, 12:05)  [code]typedef struct{ int i; float f; char* s; } Tprops; [code] Тут typedef в плюсах не нужен. Цитата(dxp @ Jan 13 2011, 08:47)  Только речь о конструкциях языка, а не о хаках И у вас "конструкции языка".
--------------------
Пишите в личку.
|
|
|
|
|
Jan 13 2011, 08:23
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(AHTOXA @ Jan 13 2011, 12:29)  А с шаблонами - это альтернативный. Я про шаблоны и говорю, что писанины больше при инициализации полей структуры-описания. В каждом конкретном определении структуры свойств придется набирать имена полей и все сопутствующее. Кроме того, шаблоны не поддерживает Embedded C++, а переходить на Extended C++ сразу утяжеляет проект ненужными фичами. Я тут подумал, можно несколько повысить быстродействие, если передавать конструктору класса не указатель на структуру-описание, а ссылку на эту структуру. Заодно и в методах классах обращение к описаниям будет выглядеть приятнее.
|
|
|
|
|
Jan 13 2011, 15:40
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Aprox @ Jan 13 2011, 16:23)  Я про шаблоны и говорю, что писанины больше при инициализации полей структуры-описания. В каждом конкретном определении структуры свойств придется набирать имена полей и все сопутствующее. Это понятно. Плюс к тому, вы получаете фактически по классу на каждый экземпляр объекта. Поэтому я и написал, "если объектов немного". Но есть у шаблонов и плюсы. Например, все ветки if () и case, зависящие от константных параметров шаблона, компилятор вычислит на этапе компиляции (то есть их не останется). То есть, код Код if (some_bool_prop1) func1(); else func2(); при some_bool_prop1 == true будет скомпилирован в Код func1(); Цитата(Сергей Борщ @ Jan 13 2011, 16:36)  За счет чего будет подъем быстродействия? Как вы представляете внутренюю реализацию ссылки кроме как через указатель? Может, для ссылки на константу есть надежда, что компилятор подставит константу прямо в код?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jan 19 2011, 18:50
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(AHTOXA @ Jan 14 2011, 11:39)  А как иначе?  Ну или можно скомпилировать оба варианта и сравнить размеры получившихся программ. Попробовал. Дисассемблером не лазил, а размеры программ сравнил. Практически неотличимо. Как передавать создаваемому объекту структуру из констант разобрался. Прошу дальнейшей помощи идейного плана. Сейчас уперся в другое. Задача стоит прорисовывать в окне разнородные объекты, например. TComboBox, TCheckBox. TRadioButton..etc., каждый имеет свое описание в виде структур констант, тоже разнотипных. Я думал создать базовый класс TObj с виртуальной функцией прорисовки и от него уже наследовать разнотипные классы, каждый со своей конкретной прорисовкой. Далее думал создать массив указателей на базовые объекты прорисовки и в цикле, по очереди вызывать функцию прорисовки базового объекта. Тупик наступил на этапе- где должен размещаться указатель на структуру описание, в базовом, или наследуемом классе? По идее в наследуемом. Но тогда до нее не доберешься из базового класса, а ведь цикл прорисовки идет именно по списку из указателей на базовые. Если структуру-констант разместить в базовом классе, то теряется вся идея, поскольку структуры все разного типа и указать конкретно один тип, базовый, не представляется возможным. Прошу совета у гуру С++ - как быть? Также прошу иметь в виду, что речь идет об ARM кристаллах, в которых RAM - маловато, а ROM- много больше. Т.е. по-прежнему загвоздка с директивой const.
|
|
|
|
|
Jan 21 2011, 07:49
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(Сергей Борщ @ Jan 20 2011, 10:51)  Как можно поместить в ROM адреса объектов, создаваемых на этапе исполнения? Ведь они создаются на стеке/в куче и их адрес заранее неизвестен. Если объекты глобальные, то можно сделать глобальный же массив указателей и его можно разместить в ROM. Да, разместить массив указателей можно в ROM, но использовать этот массив для вызова методов класса похоже нельзя. У меня лично не получается с IAR-ом. Вот простейший код: Код class Tobj { public: Tobj(){} void Draw() {cout << "Hello"; } };
Tobj obj; static const Tobj *p= &obj;
int main() { p->Draw(); return 0; } При компиляции дает ошибку в операторе p->Draw(); Код Error[Pe315]: the object has cv-qualifiers that are not compatible with the member function C:\AP\CPP\main.cpp object type is: Tobj const __data Что это значит, я затрудняюсь ответить. Если же в означенном коде убрать static const при указателе на обьект, то все прекрасно живет, но указатель оказывается в RAM!
|
|
|
|
|
Jan 21 2011, 08:10
|

тут может быть ваша реклама
    
Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280

|
Цитата(Aprox @ Jan 21 2011, 10:49)  Что это значит, я затрудняюсь ответить.
Если же в означенном коде убрать static const при указателе на обьект, то все прекрасно живет, но указатель оказывается в RAM! Вот так надо: Код static Tobj const *p= &obj; Прочитайте про квалификатор const у страуструпа или еще где. Он многогранен в зависимости от местоположения. Указатель будет константным (то есть адрес на который он будет указывать известен на этапе компиляции), а вот объект obj может меняться. Кстати можно и так: Код class Tobj { public: Tobj(){} void Draw() const {cout << "Hello"; } };
Tobj obj; static Tobj const *p= &obj;
int main() { p->Draw(); return 0; }
|
|
|
|
|
Jan 21 2011, 11:00
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(jorikdima @ Jan 21 2011, 11:10)  Вот так надо: Код static Tobj const *p= &obj; Прочитайте про квалификатор const у страуструпа или еще где. Он многогранен в зависимости от местоположения. Указатель будет константным (то есть адрес на который он будет указывать известен на этапе компиляции), а вот объект obj может меняться. Кстати можно и так: Код class Tobj { public: Tobj(){} void Draw() const {cout << "Hello"; } };
Tobj obj; static Tobj const *p= &obj;
int main() { p->Draw(); return 0; } Попробовал ваш вариант. К сожалению, компилятор IAR хоть ошибок и не выдает, но упорно размещает константный указатель р в сегменте данных, т.е. в RAM кристалла. Проверял на симуляторе Embedded Workbench IAR ver.430A
|
|
|
|
|
Jan 21 2011, 13:59
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Aprox @ Jan 21 2011, 13:00)  К сожалению, компилятор IAR хоть ошибок и не выдает, но упорно размещает константный указатель р в сегменте данных, т.е. в RAM кристалла. Что-то я не нашёл тут константного указателя. Код const object_type *ptr; object_type const *ptr; суть изменяемые указатели на константные объекты. И там, и там *ptr имеет тип object_type с квалификатором const. А сам ptr квалификаторов не имеет. Код object_type * const ptr = &some_non_constant_object; Константный указатель на изменяемый объект. Значение можно задать только при инициализации, потом указатель изменить нельзя. Код const object_type * const ptr = &some_constant_object; Константный указатель на константный объект.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jan 21 2011, 14:18
|

тут может быть ваша реклама
    
Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280

|
Цитата(ReAl @ Jan 21 2011, 16:59)  Что-то я не нашёл тут константного указателя. Код const object_type *ptr; object_type const *ptr; суть изменяемые указатели на константные объекты. И там, и там *ptr имеет тип object_type с квалификатором const. А сам ptr квалификаторов не имеет. Код object_type * const ptr = &some_non_constant_object; Константный указатель на изменяемый объект. Значение можно задать только при инициализации, потом указатель изменить нельзя. Код const object_type * const ptr = &some_constant_object; Константный указатель на константный объект. Бл***, вы правы, звездочку не справа от const, а слева надо ставить, чтоб константный указатель был. Сорри, описАлся
|
|
|
|
|
Jan 21 2011, 15:12
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(ReAl @ Jan 21 2011, 16:59)  Код object_type * const ptr = &some_non_constant_object; Константный указатель на изменяемый объект. Значение можно задать только при инициализации, потом указатель изменить нельзя. Ура! Именно так и получилось загнать константный указатель в ROM. Спасибо! Теперь могу клепать проект на С++ для ST910
|
|
|
|
|
  |
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0
|
|
|