Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[13.58.252.8] |
|
Сообщ.
#1
,
|
|
|
Глобальные переменные вроде как инициализируются нулевыми значениями.
Даже в хелпе написано: "If you don't explicitly initialize a global variable, the compiler initializes it to 0." Почему же тогда... {$APPTYPE CONSOLE} var X, Y, Z: Integer; begin WriteLn(X); WriteLn(Y); WriteLn(Z); end. 2130567168 0 0 А компилер пишет: a.pas(6) Warning: W1036 Variable 'X' might not have been initialized a.pas(7) Warning: W1036 Variable 'Y' might not have been initialized a.pas(8) Warning: W1036 Variable 'Z' might not have been initialized Где косяк? А вот код... unit a; interface var X, Y, Z: Integer; implementation end. {$APPTYPE CONSOLE} uses a; begin WriteLn(X); WriteLn(Y); WriteLn(Z); end. Не выдаёт никаких warning'ов и выдаёт нули (может, совпадение, конечно, уж не знаю). При этом я беру какую-нибудь случайную свою программу, добавляю в начало WriteLn какой-то переменной - warning'а нет... Добавляю в другую - есть. Короче, непонятно... p.s. Delphi 7, Delphi 2007, Delphi 10.1. |
Сообщ.
#2
,
|
|
|
Цитата Jin X @ If you don't explicitly initialize a global variable, the compiler initializes it to 0 Это где написано? |
Сообщ.
#3
,
|
|
|
Jin X
Зайди в отладчик в D7 и прослезись. Там кодогенератор на творил чёрти что и сбоку бантик. Он в edx(вернее ebx, esi,edi) забыл положить значение из переменной и выводит просто мусор. Я тут свой компилятор паскаля пишу. Так вот с кодогенерацией там весело. Никогда не знаешь что ты там забыл добавить и где-что сломается. Даже тесты это не всегда показывают. Цитата Jin X @ Не выдаёт никаких warning'ов и выдаёт нули (может, совпадение, конечно, уж не знаю). Это какое-то совпадение. В том смысли что наличие и отсутствие warning может зависеть от версии компилятора и установленных плагинов. Может ещё и от настроек проекта. |
Сообщ.
#4
,
|
|
|
>Это где написано?
http://docwiki.embarcadero.com/RADStudio/T...iables_(Delphi) >Почему же тогда... В XE3 нули в Debug, мусор в первой переменной (даже если изменять их количество) в Release. Видимо, дефект. |
Сообщ.
#5
,
|
|
|
Цитата Jin X @ Где косяк? Видимо дело в том, что begin..end проекта в действительности является процедурой и соотв-но переменные, объявленные в проекте, хоть и выглядят как глобальные, на самом деле являются локальными переменными этой процедуры. Добавлено Цитата Fr0sT @ Это где написано? Написано в справке. На самом деле никакой специальной инициализации нулями не делается, т.к. это получается автоматически - просто винда для секции неинициализированных данных (BSS) по дефолту выделяет обнуленные страницы памяти. |
Сообщ.
#6
,
|
|
|
Цитата Pavia @ Я думаю, тут прикол в том, что при компиляции модуля dcc не знает где эти переменные будут использоваться. А при компиляции программы dcc не знает, была ли проинициализирована переменная в модуле Это какое-то совпадение. В том смысли что наличие и отсутствие warning может зависеть от версии компилятора и установленных плагинов. Может ещё и от настроек проекта. Хотя, вот такая штука выдаёт нули (без ворнингов): unit a; interface var X, Y, Z: Integer; implementation begin WriteLn(X); WriteLn(Y); WriteLn(Z); end. Цитата leo @ ИМХО, локальные переменные - это переменные в стеке (для процедур). А так ещё переменные внутри класса могут быть и т.п. Все остальные - глобальные. А тут обращение идёт как раз к переменной (посмотрел сейчас специально через отладчик).Видимо дело в том, что begin..end проекта в действительности является процедурой и соотв-но переменные, объявленные в проекте, хоть и выглядят как глобальные, на самом деле являются локальными переменными этой процедуры. Цитата leo @ Почему же тогда здесь не нули?На самом деле никакой специальной инициализации нулями не делается, т.к. это получается автоматически - просто винда для секции неинициализированных данных (BSS) по дефолту выделяет обнуленные страницы памяти. Или дело в... Цитата Pavia @ ??? Зайди в отладчик в D7 и прослезись. Там кодогенератор на творил чёрти что и сбоку бантик. Он в edx(вернее ebx, esi,edi) забыл положить значение из переменной и выводит просто мусор. |
Сообщ.
#7
,
|
|
|
Сообщ.
#8
,
|
|
|
Цитата Jin X @ Все остальные - глобальные. А тут обращение идёт как раз к переменной (посмотрел сейчас специально через отладчик). И что увидел? Pavia прав - первые три переменные (по какой-то причине, скорее всего - какой-то доисторической совместимости) как-бы "передаются" через регистры ebx, esi, edi, но на самом деле они не инициализированы и содержат мусор. Остальные - как положено читаются из памяти и соотв-но содержат нули. Добавлено Цитата Jin X @ ИМХО, локальные переменные - это переменные в стеке (для процедур). ... Все остальные - глобальные. С точки зрения языка локальные переменные - это те, что объявлены внутри функций, а где они конкретно размещаются в памяти это, как говорится, implementation specific. Соотв-но, глобальные переменные - это те, что объявлены вне каких-либо функций. НО, на что я обращаю внимание, что по идее весь код программы состоит только из функций, соотв-но все специфические дельфийско-паскалевские фишки\плюшки типа begin-end в файле проекта или секции initialization \ finalization в юнитах по сути также являются функциями (процедурами). Т.е. весь код dpr-файла по сути является функцией и все var-переменные в этом файле можно считать "локальными" (не по способу размещения в памяти, а по области видимости - кроме функции begin-end проекта их все равно никто не видит). Видимо поэтому компилятор и считает их локальными и выдает варнинги при отсутствии их явной инициализации (и как видим - не зря). Другое дело, что эта хитрость\особенность dpr-файла не описана в справке - это да, реальный косяк |
Сообщ.
#9
,
|
|
|
Цитата leo @ Да, точно. Видимо, я не те данные зацепил (смотрел через x32dbg зачем-то)... И что увидел? Pavia прав - первые три переменные (по какой-то причине, скорее всего - какой-то доисторической совместимости) как-бы "передаются" через регистры ebx, esi, edi, но на самом деле они не инициализированы и содержат мусор. Остальные - как положено читаются из памяти и соотв-но содержат нули. Цитата leo @ Короче, прикол вот в чём. Часть переменных (в данном случае - первые 3, если мы не пытаемся, например, получить их адрес) размещаются в регистрах. Остальное - в области глобальных переменных.типа begin-end в файле проекта или секции initialization \ finalization в юнитах по сути также являются функциями (процедурами). Т.е. весь код dpr-файла по сути является функцией и все var-переменные в этом файле можно считать "локальными" (не по способу размещения в памяти, а по области видимости - кроме функции begin-end проекта их все равно никто не видит). Видимо поэтому компилятор и считает их локальными и выдает варнинги при отсутствии их явной инициализации (и как видим - не зря). {$APPTYPE CONSOLE} var A, B, C, D, E, F: Integer; begin asm lea edi,A mov eax,1 stosd inc eax stosd inc eax stosd mov ebx,10 mov esi,20 mov edi,30 end; WriteLn(A); WriteLn(B); WriteLn(C); WriteLn(D); WriteLn(E); WriteLn(F); ReadLn; end. 1 10 20 30 2 3 Теперь следующий прикол: обращение к переменной из модуля происходит не напрямую, а через указатель! Т.е. присвоение X := 1 выполняется как mov [X],1 только внутри модуля, а извне (из главной программы) - вот так: mov eax,X_addr mov [eax],1 Добавлено При этом, кстати, можно спокойно сделать вот так: asm mov X,1 end И это всё как в 7, так и в Берлине происходит. Зачем тогда так усложнять X := 1 ??? В чём прикол? Добавлено Вот в этом коде (даже при том, что Test никогда не вызывается) все переменные будут находиться в памяти (т.е. будут реальными глобальными переменными). {$APPTYPE CONSOLE} var X, Y, Z: Integer; procedure Test; begin X := 1; Y := 2; Z := 3; end; begin WriteLn(X); WriteLn(Y); WriteLn(Z); end. Добавлено Соответственно, если мы убираем строку Z := 3, эта переменная становится локальной |
Сообщ.
#10
,
|
|
|
По поводу ссылок на переменные внешних модулей: http://www.transl-gunsmoker.ru/2011/08/hac...als-faster.html
По ходу, я теперь в каждую свою прогу беде добавлять опцию {$G-} (по крайней мере, компилируемую в Delphi7) Добавлено Кстати, при создании объекта, все его поля очищаются. class function TObject.InitInstance(Instance: Pointer): TObject; {$IFDEF PUREPASCAL} var IntfTable: PInterfaceTable; ClassPtr: TClass; I: Integer; begin FillChar(Instance^, InstanceSize, 0); PInteger(Instance)^ := Integer(Self); ClassPtr := Self; while ClassPtr <> nil do begin IntfTable := ClassPtr.GetInterfaceTable; if IntfTable <> nil then for I := 0 to IntfTable.EntryCount-1 do with IntfTable.Entries[I] do begin if VTable <> nil then PInteger(@PChar(Instance)[IOffset])^ := Integer(VTable); end; ClassPtr := ClassPtr.ClassParent; end; Result := Instance; end; |
Сообщ.
#11
,
|
|
|
Это замаскированный стимул избегать глобальных переменных елико возможно)
|
Сообщ.
#12
,
|
|
|
Fr0sT,
|