Текущий архив: 2011.05.29;
Скачать: CL | DM;
Вниз
RE: getObject - Баг или фича? Найти похожие ветки
← →
GrayFace © (2011-02-11 21:33) [0]Это ответ на ветку http://delphimaster.net/view/15-1296995151/
Мда, сурово. Оказывается, Delphi не выравнивает packed record"ы в переменных. Т.е.var
b: Boolean;
bmp: tabBITMAP;
Несмотря на то, что tabBITMAP начинается с 4-байтового числа, он не будет выравнен по 4 байтам. Проверено на D2006. По-моему, это ни что иное, как огромный баг Дельфи. То, что GetObject требует выравнивания, я бы назвал скорее недокументированной особенностью, а не багом.
В любом случае, кому-нибудь надо отрепортить баг в http://qc.embarcadero.com/wc/qcmain.aspx?da=22958
Чтобы избавиться конкретно от этой ошибки, можно использоватьtype
TAlignedBitmap = record
Align: Longint;
bmType: tagBITMAP;
end;
Код, в котором баг ловится в D2006 с включенной оптимизацией и, наверное, будет пойман в других версиях:unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
glBitmap : TBitmap;
function Test2: Pointer;
var
a: Boolean;
lBmpInfo : tagBITMAP;
begin
Result:= @a;
if GetObject( glBitmap.Handle, SizeOf( tagBITMAP ), @lBmpInfo ) = 0 then
ShowMessage( "BUG" )
else
ShowMessage( "OK" );
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
glBitmap := TBitmap.Create;
glBitmap.LoadFromFile( "1.bmp" );
Test2;
end;
end.
P.S. В чем нарисован 1.bmp? Не знаешь какой-нибудь рисовалки графиков, которая может делать их в нужном для печати разрешении?
← →
tesseract © (2011-02-11 21:35) [1]
> Мда, сурово. Оказывается, Delphi не выравнивает packed record"ы
> в переменных. Т.е.
Это описано в стандарте - packed не выравнивается. Решил использовать - добивай сам.
← →
Игорь Шевченко © (2011-02-11 21:37) [2]http://www.gunsmoker.ru/2011/02/6.html
← →
Игорь Шевченко © (2011-02-11 21:37) [3]
> По-моему, это ни что иное, как огромный баг Дельфи.
это твой баг
← →
Германн © (2011-02-11 22:21) [4]
> Delphi не выравнивает packed record
Не увидел в примере ни одного packed record.
Имхо, в вопросе речь шла нескололько об ином
http://forum.sources.ru/index.php?showtopic=325143&view=showall
← →
sniknik © (2011-02-12 00:52) [5]> Не увидел в примере ни одного packed record.
сама структура tagBITMAP
и речь по ссылке не о проблемах packed record с выравниванием, а о том что сама структура для GetObject должна начинаться с выравненного адреса.
вот такая вот у него "недокументированная особенность, а не баг".
хотя, странно, в 7ке то без проблем. в нем сдвигает на границу?
← →
sniknik © (2011-02-12 01:03) [6]> в нем сдвигает на границу?
похоже так и есть, внизу столбца с опцией отключения оптимизатора есть значение Record Field Aligment, поставил на единицу, и ошибки "пошли", после не убираются даже восстановлением оригинального значения и пере компиляцией, только включением оптимизатора.
← →
Германн © (2011-02-12 04:10) [7]В обсуждении "по той ссылке" АА привёл сообщение в QC.
← →
GrayFace © (2011-02-13 02:18) [8]tesseract © (11.02.11 21:35) [1]
Это описано в стандарте - packed не выравнивается. Решил использовать - добивай сам.
Не знаю, в справке 2006 этого не сказано, только про выравнивание полей внутри самой структуры и её размер. Обещаний какого-либо выравнивания, конечно, тоже нет, но есть, скажем, утверждение Because data alignment can change, it"s a good idea to pack any record structure that you intend to write to disk or pass in memory to another module compiled using a different version of the compiler.
Игорь Шевченко © (11.02.11 21:37) [3]
это твой баг
Это либо баг языка, либо баг Windows.pas во множестве структур, т.к., по-нормальному, обращения к невыравненным данным не должно быть никогда, кроме особых случаев, когда это намеренно. Уж точно не рядовой программер должен это исправлять, создавая объемлющие структуры типаTAlignedBitmap = record
Case Integer of
1: (AlignDummy: Longint);
2: (b: tagBITMAP);
end;
Понятно, что не каждый packed record компилятор мог бы выравнять, но не выравнивать вообще - неверно.
← →
Игорь Шевченко © (2011-02-13 11:10) [9]
> Это либо баг языка, либо баг Windows.pas во множестве структур,
> т.к., по-нормальному, обращения к невыравненным данным
> не должно быть никогда
Ты кто такой, чтобы утверждать, что должно быть, а что нет ? Автор Windows, автор компилятора, или кто ?
← →
sniknik © (2011-02-13 16:51) [10]> обращения к невыравненным данным не должно быть никогда, кроме особых случаев, когда это намеренно.
слово packed как раз говорит о такой намеренности. проконсультируйся у справки.
также как значение "отключить оптимизатор" говорит о желании получить код "как есть", без правок оптимизатора.
т.е. в обоих случаях что хотел то и получил.
> Уж точно не рядовой программер должен это исправлять
а кто? если сам этот рядовой программер сказал - "хочу именно так, и не иначе". ... но напоровшись на собственное не знание особенностей некоторых функций, срочно передумал, типа "хочу именно так. но с изменениями где будут ошибки"... ???
> создавая объемлющие структуры типа
этого и не нужно... т.к. структура тут не причем (можно и ей конечно сделать выравнивание... но смысл7 это только запутывает все).
по ссылке
http://forum.sources.ru/index.php?showtopic=325143&view=showall
пост
CodeMonkey Сообщ. #9 от 7.02.11, 23:16
в примере же все очевидно показано -T1 := Windows.GetObject( glBitmap.Handle, SizeOf( tagBITMAP ), @Buffer);
T2 := Windows.GetObject( glBitmap.Handle, SizeOf( tagBITMAP ), PByte(@Buffer) + 1);
T3 := Windows.GetObject( glBitmap.Handle, SizeOf( tagBITMAP ), PByte(@Buffer) + 2);
T4 := Windows.GetObject( glBitmap.Handle, SizeOf( tagBITMAP ), PByte(@Buffer) + 3);
структура одна и та же "сжатая"/не выровненная, меняется начальный адрес, ссылка на нее, значение указателя... с разными результатами.
т.е. задается, для примера
ptr[$100:$0] - работает
ptr[$100:$1] - не работает
ptr[$100:$2] - работает
ptr[$100:$3] - работает
и т.д.
функция попросту игнорирует младший бит из указателя, хотя никаких предупреждений в хелпе винды, о "строгой четности" значения переменной данного указателя нет.
> Ты кто такой, чтобы утверждать, что должно быть, а что нет ? Автор Windows, автор компилятора, или кто ?
ни один из, но ставлю на баг винды...
← →
sniknik © (2011-02-13 16:51) [11]> ptr[$100:$3] - работает
ptr[$100:$3] - не работает
← →
Игорь Шевченко © (2011-02-13 17:15) [12]
> но ставлю на баг винды...
на неполноту документации по функции GetObject
← →
Германн © (2011-02-13 18:01) [13]
> на неполноту документации по функции GetObject
>
И на явную ложь в дельфийском хелпе по поводу GetLastError для этой функции.
← →
clickmaker © (2011-02-13 18:12) [14]> И на явную ложь в дельфийском хелпе
дельфийский хелп по вин32 лучше сразу фтопку. msdn - наше всё
← →
Anatoly Podgoretsky © (2011-02-13 18:55) [15]> clickmaker (13.02.2011 18:12:14) [14]
Никакого дельфийский хелпа по вин32 не существует, это микрософтовский хелп,
часть MSDN, сильно устрареший, все таки ему уже 12 лет.
← →
Германн © (2011-02-14 01:46) [16]
> msdn - наше всё
Кстати. Если судить по online msdn, которое можно сейчас найти, это всё-таки баг Windows. Который нашли, но не исправили, а просто убрали из описания функции строку о GetLastError. Но возможно не везде убрали или не везде это баг. Например в описании этой функции для Windows CE эта строка присутствует.
Ну и как теперь отлаживать программы, если функция WinAPI возвращает ноль, т.е. в данном случае ошибку, если нельзя эту ошибку идентифицировать?
← →
DiamondShark © (2011-02-14 12:15) [17]Данные в стеке должны выравниваться.
Это баг компилятора, он не должен был положить в стек локальную переменную размером в 1 байт.
← →
sniknik © (2011-02-14 12:25) [18]> DiamondShark © (14.02.11 12:15) [17]
а ты уверен что все правильно понял? баг проявляется при отключенной оптимизации, т.е. компиляции "as is", как получилось так и получите, или при установленном выравнивании = 1 байт, т.е. отключенной.
по каким причинам пользователь это делает неважно, может исследует возможность уменьшить размер "на блохах", главное компилятором это делается по явному указанию программиста.
← →
DiamondShark © (2011-02-14 12:33) [19]Удалено модератором
← →
Anatoly Podgoretsky © (2011-02-14 12:58) [20]
> Это баг компилятора, он не должен был положить в стек локальную
> переменную размером в 1 байт.
Может и должен, но займет она все равно 4 байта и стек всегда выровнен на границу 32 бит.
← →
DiamondShark © (2011-02-14 13:02) [21]
> Anatoly Podgoretsky © (14.02.11 12:58) [20]
Однако, как видим, не заняла и не выровнен.
Следующую переменную компилятор влепил на границе байта. В стеке.
← →
sniknik © (2011-02-14 15:16) [22]> но займет она все равно 4 байта
а если их 2-3 переменных по байту, тогда 8-12? а если они объединены в структуру которая гарантирует "сжатое" без выравнивания расположение переменных. (пакет рекорд).?
> и стек всегда выровнен на границу 32 бит.
стек да, как и адрес вызова функции (вроде бы), но не адресное пространство в нем... т.е. не данные, про них нигде не сказано, что они обязаны выравниваться. могут, для ускорения, но не обязаны.
p.s. вы типа никогда на асме не писали, стек это такая же память, единственно адресуется своим регистром, а у com-прог в дос-е, так вообще были все сегменты совмещены, кода/данных/стек и ничего, никогда не приходилось каждую байтовую переменную с четного адреса начинать, только потому, что "там стек. О!".
← →
Игорь Шевченко © (2011-02-14 15:19) [23]Anatoly Podgoretsky © (14.02.11 12:58) [20]
> стек всегда выровнен на границу 32 бит.
стек не может быть выровнен, может быть выровнен указатель стека
← →
GrayFace © (2011-02-14 23:12) [24]Игорь Шевченко © (13.02.11 11:10) [9]
Ты кто такой, чтобы утверждать, что должно быть, а что нет ? Автор Windows, автор компилятора, или кто ?
Я эукариот.
sniknik © (13.02.11 16:51) [10]
а кто? если сам этот рядовой программер сказал - "хочу именно так, и не иначе". ... но напоровшись на собственное не знание особенностей некоторых функций, срочно передумал, типа "хочу именно так. но с изменениями где будут ошибки"... ???
Рядовой программер ничего не говорит, он пишит программу, в которой самой по себе нет ошибок, а получает, что она не работает (в случае GetObject) или работает медленнее (остальные не выравневающиеся структуры из Windows.pas). Отключение оптимизации в примере из моего первого поста не требуется для воспроизведения бага.
sniknik © (13.02.11 16:51) [10]
этого и не нужно... т.к. структура тут не причем (можно и ей конечно сделать выравнивание... но смысл7 это только запутывает все).
Почему? Есть баг - нужно делать work around, чтобы гарантированно работало.
sniknik © (14.02.11 15:16) [22]
> и стек всегда выровнен на границу 32 бит.
стек да, как и адрес вызова функции (вроде бы),
Нет, адрес функции может быть нечетным, как и адрес возврата.
Страницы: 1 вся ветка
Текущий архив: 2011.05.29;
Скачать: CL | DM;
Память: 0.54 MB
Время: 0.012 c