Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
| | | | |
VC в debug режиме тоже 04.10.05 11:47 Число просмотров: 2129
Автор: amirul <Serge> Статус: The Elderman Отредактировано 04.10.05 11:51 Количество правок: 1
|
> *nix константы в readonly памяти держит. > char *ptr = "core dumped."; > *ptr = 'C'; > Эта строка приведет к сегментэйшн фолт.
вот кусок листинга в дебажном режиме
PUBLIC _main
PUBLIC ??_C@_0N@LCLI@core?5dumped?4?$AA@ ; `string'
; COMDAT ??_C@_0N@LCLI@core?5dumped?4?$AA@
; File d:\work\test\test.c
CONST SEGMENT
??_C@_0N@LCLI@core?5dumped?4?$AA@ DB 'core dumped.', 00H ; `string'
CONST ENDS
; COMDAT _main
_TEXT SEGMENT
_ptr$ = -4
_main PROC NEAR ; COMDAT
; 2 : main() {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 ec 44 sub esp, 68 ; 00000044H
00006 53 push ebx
00007 56 push esi
00008 57 push edi
00009 8d 7d bc lea edi, DWORD PTR [ebp-68]
0000c b9 11 00 00 00 mov ecx, 17 ; 00000011H
00011 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00016 f3 ab rep stosd
; 3 : char *ptr = "core dumped.";
00018 c7 45 fc 00 00
00 00 mov DWORD PTR _ptr$[ebp], OFFSET FLAT:??_C@_0N@LCLI@core?5dumped?4?$AA@ ; `string'
; 4 : *ptr = 'C';
0001f 8b 45 fc mov eax, DWORD PTR _ptr$[ebp]
00022 c6 00 43 mov BYTE PTR [eax], 67 ; 00000043H
; 5 : }
00025 5f pop edi
00026 5e pop esi
00027 5b pop ebx
00028 8b e5 mov esp, ebp
0002a 5d pop ebp
0002b c3 ret 0
_main ENDP
_TEXT ENDS
---
Для констант выделяется отдельный сегмент. А в релизе наверное подумали, что 4 килобайта (лишний сегмент) только для того, чтобы сунуть туда десяток байт - сильно расточительно и выглядит это так:
PUBLIC _main
PUBLIC ??_C@_0N@LCLI@core?5dumped?4?$AA@ ; `string'
; COMDAT ??_C@_0N@LCLI@core?5dumped?4?$AA@
; File D:\Work\test\test.c
_DATA SEGMENT
??_C@_0N@LCLI@core?5dumped?4?$AA@ DB 'core dumped.', 00H ; `string'
_DATA ENDS
; COMDAT _main
_TEXT SEGMENT
_main PROC NEAR ; COMDAT
; 3 : char *ptr = "core dumped.";
; 4 : *ptr = 'C';
00000 c6 05 00 00 00
00 43 mov BYTE PTR ??_C@_0N@LCLI@core?5dumped?4?$AA@, 67 ; 00000043H
; 5 : }
00007 c3 ret 0
_main ENDP
_TEXT ENDS
---
Не знаю. Если записать побольше констант может им и выделят отдельный сегмент. В любом случае стандарт ничего об этом не говорит (отдает на откуп реализации).
Чтобы не надеяться ни на кого в Visual C можно использовать перед объявлением этой константы
#pragma const_seg(push, ".text")
и
#pragma const_seg(pop)
после
А можно и вообще слить секцию констант с секцией данных или кода (в опциях/ключах линкера или #pragma comment(linker, ...))
Это все касается vc, в остальных компиляторах нечто подобное тоже должно быть.
> > Это ж какой компайлер не понимает стандарта 98-го > года?
> BCC V3.1 от 1992 года и SC V7.2 от 1995 года. > Первый можно кастрировать до необычайно маленьких размеров > так чтоб такать с собой буквально на дискетке. Второй > правильно работает с памятью.
Флешки 128 метровые стоят меньше 20 баксов. Или дискеты это принципиально?
> Попробую.
Не забудь поколдовать над секцией констант, если эта константа глобальная или статическая (в функции/классе), если же это просто
struct A {
int a;
};
void f(const A *a) {
((A *)a)->a = 100;
}
int
main() {
A *a = new A;
A b;
f(a);
f(&b);
return 0;
}
---
То бишь переменная выделена в обычной памяти, но const запрещает ее изменять, то преобразование типов - то что нужно.
|
<programming>
|
[C++] Инициализация константных объектов. 30.09.05 18:08
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
|
Многие компиляторы размещают константные переменные в readonly памяти. Интересно, как они поступают с константными объектами, ведь вызывающийся до выполнения основной части программы конструктор должен проинициализировать объект?
И еще. Возмем, скажем "operator+". Обязательно, или полезно, или не стОит, или нельзя описывать аргументы ссылками на константы. Теоретически они меняться не должны, но если имеет место быть ситуация, когда логически объект не меняется, но надо что-то щелкнуть служебное, например счетчик обращений. Какие-нибудь рекомендации есть в этом направлении?
|
|
Даже конструктор не всегда вызывается. Один из самых... 03.10.05 11:04
Автор: amirul <Serge> Статус: The Elderman
|
> Многие компиляторы размещают константные переменные в > readonly памяти. Интересно, как они поступают с > константными объектами, ведь вызывающийся до выполнения > основной части программы конструктор должен > проинициализировать объект?
Даже конструктор не всегда вызывается. Один из самых распространенных способов использования констант - глобальные (или статические в классе) целочисленные переменные, которые инициализируются прямо на месте. В этом случае оптимизатор заменяет все обращения к константе на ее значение, а линкер вырезает неиспользуемую переменную. Результат - в точности такой же как и при использовании #define, но с типизацией.
> И еще. Возмем, скажем "operator+". Обязательно, или > полезно, или не стОит, или нельзя описывать аргументы > ссылками на константы. Теоретически они меняться не должны,
Общая рекомендация при использовании ссылок при передаче параметров: если функция не собирается менять содержимое, ее надо объявлять const. Это не требование языка, а просто стилистическая рекомендация. Таким образом будет видно, если передана неконстантная ссылка, то в нее возвращается какое то значение.
> но если имеет место быть ситуация, когда логически объект > не меняется, но надо что-то щелкнуть служебное, например > счетчик обращений. Какие-нибудь рекомендации есть в этом > направлении?
Ключевое слово mutable придумано специально для таких целей: счетчики ссылок/кеширование и пр. изменения ПРЕДСТАВЛЕНИЯ, которое логически не изменяют сам объект.
|
| |
Ну не всегда константный элемент объекта может... 03.10.05 11:25
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman Отредактировано 03.10.05 11:26 Количество правок: 1
|
> Даже конструктор не всегда вызывается. Один из самых > распространенных способов использования констант - > глобальные (или статические в классе) целочисленные > переменные, которые инициализируются прямо на месте. В этом > случае оптимизатор заменяет все обращения к константе на ее > значение, а линкер вырезает неиспользуемую переменную. > Результат - в точности такой же как и при использовании > #define, но с типизацией.
Ну не всегда константный элемент объекта может инициализироваться константой. Может это быть и переменная, и системный параметр (текущее время, например), и что-то считанное из файла.
> Общая рекомендация при использовании ссылок при передаче > параметров: если функция не собирается менять содержимое, > ее надо объявлять const. Это не требование языка, а просто > стилистическая рекомендация. Таким образом будет видно, > если передана неконстантная ссылка, то в нее возвращается > какое то значение. > > Ключевое слово mutable придумано специально для таких > целей: счетчики ссылок/кеширование и пр. изменения > ПРЕДСТАВЛЕНИЯ, которое логически не изменяют сам объект.
Мои архаичные копайлеры "mutable" не поймут, ничего, смирюсь в ворнингами.
|
| | |
Ну да. Я просто сказал о наиболее частом использовании. Если... [upd] 03.10.05 13:15
Автор: amirul <Serge> Статус: The Elderman Отредактировано 03.10.05 13:17 Количество правок: 1
|
> Ну не всегда константный элемент объекта может > инициализироваться константой. Может это быть и переменная, > и системный параметр (текущее время, например), и что-то > считанное из файла.
Ну да. Я просто сказал о наиболее частом использовании. Если оптимизатор не сможет заменить все обращения к константе на ее значение (неизвестное на этапе компиляции), то он просто заведет переменную (вернее он ее заведет в любом случае, но линкер не сможет отрезать "неиспользуемый код"). В случае x86 платформ (что *nix, что винды) никакой readonly памяти не будет. Переменная просто попадет в секцию данных (это если статическая или глобальная) или там же где и все остальные (стек/куча/ручная выделялка), а все попытки обратиться к ней на изменение будут пресекаться на этапе компиляции.
> Мои архаичные копайлеры "mutable" не поймут, ничего, > смирюсь в ворнингами.
Это ж какой компайлер не понимает стандарта 98-го года? Семь лет прошло как никак - было время привести в соответсвтие так сказать (и это не export, который так до сих пор никем толком и не поддерживается, ибо не совсем понятно как сделать его реализацию)
-----------
Да, кстати, если компилятор таки не понимает стандарта 98-го года, то можно использовать const_cast (из того же стандарта, если он хотя бы частично реализован) ну или c-style cast (обычные скобки) для отрезания константности из типа. Некошерно, зато работать будет и компиляться без ворнингов.
|
| | | |
*nix константы в readonly памяти держит. 03.10.05 16:49
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
|
> Ну да. Я просто сказал о наиболее частом использовании. > Если оптимизатор не сможет заменить все обращения к > константе на ее значение (неизвестное на этапе компиляции), > то он просто заведет переменную (вернее он ее заведет в > любом случае, но линкер не сможет отрезать "неиспользуемый > код"). В случае x86 платформ (что *nix, что винды) никакой > readonly памяти не будет. Переменная просто попадет в > секцию данных (это если статическая или глобальная) или там > же где и все остальные (стек/куча/ручная выделялка), а все > попытки обратиться к ней на изменение будут пресекаться на > этапе компиляции.
*nix константы в readonly памяти держит.
char *ptr = "core dumped.";
*ptr = 'C';
Эта строка приведет к сегментэйшн фолт.
> Это ж какой компайлер не понимает стандарта 98-го года?
BCC V3.1 от 1992 года и SC V7.2 от 1995 года.
Первый можно кастрировать до необычайно маленьких размеров так чтоб такать с собой буквально на дискетке. Второй правильно работает с памятью.
> Семь лет прошло как никак - было время привести в > соответсвтие так сказать (и это не export, который так до > сих пор никем толком и не поддерживается, ибо не совсем > понятно как сделать его реализацию)
> Да, кстати, если компилятор таки не понимает стандарта > 98-го года, то можно использовать const_cast (из того же > стандарта, если он хотя бы частично реализован) ну или > c-style cast (обычные скобки) для отрезания константности > из типа. Некошерно, зато работать будет и компиляться без > ворнингов.
Попробую.
|
| | | | |
VC в debug режиме тоже 04.10.05 11:47
Автор: amirul <Serge> Статус: The Elderman Отредактировано 04.10.05 11:51 Количество правок: 1
|
> *nix константы в readonly памяти держит. > char *ptr = "core dumped."; > *ptr = 'C'; > Эта строка приведет к сегментэйшн фолт.
вот кусок листинга в дебажном режиме
PUBLIC _main
PUBLIC ??_C@_0N@LCLI@core?5dumped?4?$AA@ ; `string'
; COMDAT ??_C@_0N@LCLI@core?5dumped?4?$AA@
; File d:\work\test\test.c
CONST SEGMENT
??_C@_0N@LCLI@core?5dumped?4?$AA@ DB 'core dumped.', 00H ; `string'
CONST ENDS
; COMDAT _main
_TEXT SEGMENT
_ptr$ = -4
_main PROC NEAR ; COMDAT
; 2 : main() {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 ec 44 sub esp, 68 ; 00000044H
00006 53 push ebx
00007 56 push esi
00008 57 push edi
00009 8d 7d bc lea edi, DWORD PTR [ebp-68]
0000c b9 11 00 00 00 mov ecx, 17 ; 00000011H
00011 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00016 f3 ab rep stosd
; 3 : char *ptr = "core dumped.";
00018 c7 45 fc 00 00
00 00 mov DWORD PTR _ptr$[ebp], OFFSET FLAT:??_C@_0N@LCLI@core?5dumped?4?$AA@ ; `string'
; 4 : *ptr = 'C';
0001f 8b 45 fc mov eax, DWORD PTR _ptr$[ebp]
00022 c6 00 43 mov BYTE PTR [eax], 67 ; 00000043H
; 5 : }
00025 5f pop edi
00026 5e pop esi
00027 5b pop ebx
00028 8b e5 mov esp, ebp
0002a 5d pop ebp
0002b c3 ret 0
_main ENDP
_TEXT ENDS
---
Для констант выделяется отдельный сегмент. А в релизе наверное подумали, что 4 килобайта (лишний сегмент) только для того, чтобы сунуть туда десяток байт - сильно расточительно и выглядит это так:
PUBLIC _main
PUBLIC ??_C@_0N@LCLI@core?5dumped?4?$AA@ ; `string'
; COMDAT ??_C@_0N@LCLI@core?5dumped?4?$AA@
; File D:\Work\test\test.c
_DATA SEGMENT
??_C@_0N@LCLI@core?5dumped?4?$AA@ DB 'core dumped.', 00H ; `string'
_DATA ENDS
; COMDAT _main
_TEXT SEGMENT
_main PROC NEAR ; COMDAT
; 3 : char *ptr = "core dumped.";
; 4 : *ptr = 'C';
00000 c6 05 00 00 00
00 43 mov BYTE PTR ??_C@_0N@LCLI@core?5dumped?4?$AA@, 67 ; 00000043H
; 5 : }
00007 c3 ret 0
_main ENDP
_TEXT ENDS
---
Не знаю. Если записать побольше констант может им и выделят отдельный сегмент. В любом случае стандарт ничего об этом не говорит (отдает на откуп реализации).
Чтобы не надеяться ни на кого в Visual C можно использовать перед объявлением этой константы
#pragma const_seg(push, ".text")
и
#pragma const_seg(pop)
после
А можно и вообще слить секцию констант с секцией данных или кода (в опциях/ключах линкера или #pragma comment(linker, ...))
Это все касается vc, в остальных компиляторах нечто подобное тоже должно быть.
> > Это ж какой компайлер не понимает стандарта 98-го > года?
> BCC V3.1 от 1992 года и SC V7.2 от 1995 года. > Первый можно кастрировать до необычайно маленьких размеров > так чтоб такать с собой буквально на дискетке. Второй > правильно работает с памятью.
Флешки 128 метровые стоят меньше 20 баксов. Или дискеты это принципиально?
> Попробую.
Не забудь поколдовать над секцией констант, если эта константа глобальная или статическая (в функции/классе), если же это просто
struct A {
int a;
};
void f(const A *a) {
((A *)a)->a = 100;
}
int
main() {
A *a = new A;
A b;
f(a);
f(&b);
return 0;
}
---
То бишь переменная выделена в обычной памяти, но const запрещает ее изменять, то преобразование типов - то что нужно.
|
|
|