DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: swegfrt
今日帖子: 0
在线用户: 1
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/22 22:48:46
标题:
Delphi and Its Obscure Behaviors! BUG! UnManaged types are UnInitialized = valid Pointer and Value 浏览:807
加入我的收藏
楼主: Delphi and Its Obscure Behaviors! BUG! BUG! BUG!

Today, doing some tests to answer some questions from internet users, I came across a situation, until then, never faced!

First, let's describe the scenario in use:
- MSWindows 10 21H2
- RAD Studio 11.1 Alexandria
- VCL project 32bit (nothing special)
- 1 Form main (created by IDE - automatically)
- 1 Form second (not used at all - just is in my project)
- 1 Button to tests!

Now the question itself:


procedure TForm1.Button1Click(Sender: TObject);
var
  MyHelloVar: TForm;
begin
  MyHelloVar.Close; // what this do it? Raise to "Access Violation" or Not?
end;


Well, this command should, in fact, throw an "Exception" (or an "Access Violation" error).

But in fact it does not throw any error. And yet, it executes the command "CLOSE" correctly.

Now comes the explanation: This is another one of Delphi's "Bugs" (which I hadn't come across yet).

As explained by engineer "Andreas Rejbrand":

"Local variables of unmanaged types (like class types, like TForm) are uninitialized, so you are calling TForm.Close on a random pointer (whatever happens to be in your computer's RAM at that place). Then anything can happen. Different things can happens every time you run the code. This is a bug."


So, stay tuned!

In Delphi, a wrong command is not always a command error!


So never fully trust reviews like:

If Assigned( xxxxxx ) then
....

or

If not(xxxx = nil) then
....

Because, really, it is not always possible to know whether or not a variable (object instance) was actually created.

Therefore, the procedure "Destroy" should not be called (directly) from any object, such as: MyForm.Destroy;

Hello World! :_>
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/6/23 8:34:44
1楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 10:09:35
2楼: 测试了一下,很有意思的一个现象:
Form2内容如下:
type
  TForm2 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
    XXX:string;
    DataArray:array[0..100] of array[0..100] of Integer;

    procedure SayHello;
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

{ TForm2 }

procedure TForm2.SayHello;
begin
  ShowMessage('Hello from Form2 and XXX='+XXX);
end;

----------
主窗体Form1的内容:
var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var
  F2: TForm2;
begin
  if Assigned(F2) then
  begin
// F2.SayHello;   //1
// F2.XXX:='xxxxx';  //2

    ShowMessage('F2.DataArray.Size=' + Length(F2.DataArray).ToString); //3
    ShowMessage('F2.XXX=' + F2.XXX);  //4
  end
  else
    ShowMessage('F2 Not exists');
end;

特意在Project设置里禁止自动生成Form2
在debug模式下,//3 OK ,//4 AVz错误
在release模式下,//3和//4都OK
在release模式下,如果注释掉2,3,4,只保留1,会AV错误;注释掉2,3,保留1,4,OK

----------
小结一下:
似乎在debug模式下,D11编译器默认初始化了F2变量和F2内部的值型变量(在栈上初始化的?),但是没有初始化F2内部的“非值型”变量(要在堆上初始化的?)
在release模式下,D11编译器不仅初始化了F2变量和F2内部的值型变量,还初始化了代码中出现的“非值型”变量?
----------------------------------------------
-
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 10:32:49
3楼: I finally understand why some people desperately want to delete the pointer in Delphi. Because he can't understand the pointer. These people have exerted a very bad influence on the development of Delphi.
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 10:35:23
4楼: @3楼 怎么understand的给讲讲呗
----------------------------------------------
-
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 10:38:26
5楼: 你可以试试

TForm2($0040001).SayHello;
TForm2($0040002).SayHello;
TForm2($0040003).SayHello;

TForm2(266240).SayHello;

甚至
TForm2(0).SayHello;
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 10:44:29
6楼: 上面这5行无论debug还是release模式都是AV错误啊

这个$0004_000x的地址是有特殊的意义么?
----------------------------------------------
-
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 10:51:39
7楼: procedure TForm2.SayHello;
begin
//ShowMessage('Hello from Form2 and XXX='+XXX); 改成如下,你再试试

  ShowMessage('Hello from Form2 and XXX=');
end;
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 10:54:32
7楼: 感觉楼主的意思是说:
按照正常的逻辑,
没有初始化的指针型变量就应该指向0地址,
这样Assigned或者nil判断才有意义,
D11的编译器显然没有遵守这个“正常的逻辑”
意味着说,在D11环境下,不能用Assigned和nil来判断一个指针型变量(比如类的实例)有没有被初始化,
在这种语境下安全的方式似乎是先FreeAndNil,然后再显性create
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 11:16:15
8楼: @7楼,这个肯定没问题啊,
把一段内存强制转换成一个类的实例,
如果类内部的方法没有调用这段内存存储的值
那么这个方法能正常运行也是合理的
毕竟方法的实现没有存储在这段内存区
----------------------------------------------
-
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 11:28:23
9楼: 栈上的内存为什么要初始化。 那么 Integer, Double都初始化,其代价就是程序都变慢。
程序员的职责,丢给编译器,让程序运行期处理,这是脚本语言才干的事情。
编译器能在编译期间给代码编写者警告,已经足够了。
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 11:45:42
10楼: @9楼 我大概理解您的意思了,程序员应该自己处理自己要用到的东西

另一方面,其实上面的代码无论是debug还是release模式编译,D11都没有给出警告

D11编译器会把全局的指针变量指向0地址(这时候用Assigned和nil判断符合预期,也符合逻辑)
D11编译器对局部指针变量不做处理,指向哪儿是哪儿,因为这部分代码本地可见,本来就该程序员负责,这时候就不需要,也不能用Assigned或nil来判断

这个应该算是一个特性
----------------------------------------------
-
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/6/23 11:49:07
10楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 12:08:28
11楼: 呃,C语言也不初始化啊……
怎么才算“正常的逻辑”。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 12:12:40
12楼: PS:C里面还有更加过分的。
具体的函数忘了,字符串拷贝一类的。

微软的实现,会检查是否越界。
Linux下,不检查越界。并带注释解释:这个函数只拷贝数据,是否越界应由程序开发者自己判断。。。

当然不会报错,也没有警告。
只是同一个程序在Windows向下正常,Linux下偶然会因越界引发难以预计的问题。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 12:14:16
12楼: 感谢蒲石的回帖指导,纠正了我的一个认知错误,感谢
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 12:17:07
13楼: PS:数据库里面substr取子串。
下面几个数据库,index都应该从1开始,但是写0也不报越界错:

Oracle : substr(name,0,2) 等价于 substr(name,1,2) :取得2个字符。
PostgreSQL : substr(name,0,2) 等价于 substr(name,1,1) :取得1个字符。
MySQL : substr(name,0,2) :取不到任何东西。

我想说的大概是,没有什么理所当然正常的逻辑。。。

咱从小说汉语长大的,但不代表所有人都应该说汉语。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 12:22:56
14楼: 相当于,
到什么山唱什么歌,
严格遵守当地法律法规
否则就是经验主义害死人

👍
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 12:27:11
14楼: 就算用Java,golang也不是啥都能自动GC的。
该try with resource的,该注意生命周期的。

再基本的东西,需要你来处理,你就逃不掉。。。

反正,无论用什么语言,都需要理解和遵循它的方式。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 12:33:59
15楼: delphi里面我觉得比较坑的是那个borlandmm.dll。具体应该是delphi7时代。

比如调用DLL时传了String,也许开发测试都没事儿,上线了就等着神秘报错吧。
我们10多年前就中招过。
正确的做法是自己分配空间,传地址进去(pchar)。

但是后来据说delphi2006改用了fastmm,问题就解决了。
甚至可以通过替换dll,让delphi7也能DLL传String了???(俺怕了,没试过)。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 12:35:13
15楼: 趁着大佬在,再请教一个之前讨论的问题:

在写底层库的时候,
如果发生异常,
是直接抛出异常好,
还是返回一个错误代码好,
有没有一个认可度比较高的结论?
还是笼统说的,要具体问题具体分析?

我记得之前讨论的一个结果是:
如果返回错误代码,需要配套的文档来说解释这个错误代码
如果抛出异常,需要在调用层try catch
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 12:38:36
16楼: @15楼 delphi环境下从来不敢给dll传入或者导出string参数,
尽管现在Delphi在写dll的时候会在代码模板里用大段注释来说明这个问题
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 12:45:41
16楼: 回到主题,都这么写吧?

var
  abc:TForm // TAnyThing
begin
  try
    ...
    abc=nil;
    //init the var abc in your own way.
    ...
  except
    ...
    if Assigned(abc) then
      FreeAndNil(abc)
    ...
  end;
----------------------------------------------
Bye bye DDRFAN...
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 12:55:36
17楼: abc:=nil这一行和下面if Assignedxxxx这一样都可以不要吧

下面这样是不是好一点?
try
  //初始化abc
  //其他操作
finally
   FreeAndNil(abc);
end;
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/23 13:14:30
18楼: I think the big problem with "Object Pascal" about valid "pointers", like my initial post, it's that the compiler generate randomics values to initializate the vars or objects!

I my sample, you can see that "MyHelloVar" is not really = nil or null value. Because "MyHelloVar : TForm", where "TForm" is a reference to a class, so, "MyHelloVar = something" not "MyHelloVar = NOTHING".

for that, Assigned(MyHelloVar)=IsNotNIl or (MyHelloVar=nil)=IsFALSE
because "MyHelloVar=AddressUsedByTFormOnMemory" be "0", or any other value.

For this, it's always recomended initializate any var_or_object before your use, for example;

var
  MyVar:string;   // managed by compiler == a garbage-collector take care
  MyFrm:TMyFormX; // unmanaged 
begin
  MyVar:='';
  MyFrm:=nil;
  try ... finally ...
    MyFrm.Free; // OK because Free verify if "Self=nil"
...
end;

 Self = my instance_object 
----------
  if Self=nil =  "IF" my pointer used to reference my var_instance is nil or not!
 
  if NOT nil then FREE IT!
----------
the object will be released from memory, BUT YOUR DATAs NOT!

The data of my object still on memory until the memory be necessary to another object or any other.

then, this action, create this stranger beraviours!

new vars appointing for old data on memory!

this topic it's really complex to understand at all.
Many enginners and MVP have distincts understooding about it
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 13:52:22
19楼: The core issue is the use of stacks. An instruction to modify the ESP register can quickly allocate memory. No GetMem, No AllocMem. It is the fastest.
This is determined by the underlying mechanism. For string type, its memory allocation is not on the stack at all. What I want to say is that you need to understand the difference. Understand how assembly code implements these features. Maybe you will have a different view. In my opinion, if this is a bug and be fixed. Then, Delphi has no use value.
----------------------------------------------
-
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/6/23 13:52:58
19楼: @emailx45 
For local vars, Delphi just gives a position to reference it and keep it as is. Coder should & must guarantee the initialization and cleanup working as expected.
----------------------------------------------
-
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/6/23 14:09:32
20楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 14:10:53
20楼:
It is this demand that can not clearly establish the positioning of Delphi language that leads to a lot of useless efforts.

For example, ARC wants to solve all the life cycle problems. It completely ignores the orientation of native language. Leading to 10 years of waste.

If the positioning of Delphi is consistent with PHP and JavaScript, then it is pretty good. But Delphi is not a script, it is native, it must runs fastest.

All these effort try to slow down Delphi. It's so sad.
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/23 14:18:36
21楼: After all that's been said, I think that if there isn't a market for every single programming language out there today, then they've died of their own accord.

But as we see, there are millions of people with countless and precious abilities, so there will always be a place in the sun for everyone.

Of course, it is the "market" who determines whether or not something is relevant.

He was the determining factor for the Silk Road and all other forms and means of homo-sapiens expansion.

If there is a market, there will be a programmer dissatisfied with his own achievements!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 zwjchinazwj (蒲石) ★☆☆☆☆ -
普通会员
2022/6/23 14:33:03
22楼: I don't think there is a market for Delphi scripting.
 On the contrary, it will lose all its advantages.

By the way. You can definitely consider using dwscript.
----------------------------------------------
-
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/6/23 17:24:05
23楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2022/6/23 21:50:38
24楼: @17楼
这贴就是在讲对象指针不会自动初始化0值呀。

如果不赋0值(nil),
下面初始化失败后,
会在随机地址进行释放abc的操作。。。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/23 22:27:05
25楼: I dont want to say nothing about "Delphi ScriptED"! nothing! nothing!

my English is very poor!!! SORRYYYYYYYYYY....
----------
I meant: "IF" there is a market for a product, "THEN" there will be someone to consume it!!! And SO, there will always be someone DISSATISFIED, too!
----------

My ignorance is bigger than the universe  :))))
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/23 22:43:48
26楼: I'll go try explain my vision ok?

I'm NOT EXPERT AT ALLLLLLLLLL......

FREE ==> "mark" the object-instance to receive a "nil" value if Count-Reference is 0... like a "delete" in DB... after this, you can do the "COMMIT" real ( xxxx := NIL ) then the memory it's released for another tasks.


FreeAndNil(...) ==> verify and release it "IF" the vars (itself) is a var-pointer have a valid assignement to a valid object.
For that, FreeAndNil() dont "crash" if a var-object is nil

---------
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  MyStrangerBehaviousInDelphi: TForm;
begin
  ShowMessage(integer(pointer(Self)).ToString);
  //
  try
    MyStrangerBehaviousInDelphi.Free; // works = no "AV" = works like "Self.HIDE()" = Form1.HIDE()
    //
    // MyStrangerBehaviousInDelphi:=nil; // comment and uncomment for test 
    // FreeAndNil(MyStrangerBehaviousInDelphi); // works = no "AV" = works like "Self.HIDE()" = Form1.HIDE()
    //
    // FreeAndNil(nil); // works! BUT you have a "Access Violation" or an "EAccessViolation exception" -- "nil^"  does not possible!
    //
    ShowMessage(integer(pointer(MyStrangerBehaviousInDelphi)).ToString);
    /// after... you have a "Abstract error" == the function exists (ToString), but the obj is gone!
  except
    on E: Exception do
      ShowMessage('My Except = ' + E.ClassName + sLineBreak + E.Message);
  end;
end;

end.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/6/23 23:57:21
27楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/24 0:24:26
28楼: for me, "VALID" it's all that exists and "it" is type expected"!
something "that exists", but it's not the "type expected", it's not valid!

this is valid concept in Delphi too...

look the "warning message":  "mismatched type", when we try to assign a value to a var-object that expects a specific "type"-value.

common situations where the code expected a value, and receive another!
in runtime, you'll have a "exception" as way to show that "something it's wrong in your code"!

procedure TForm1.Button1Click(Sender: TObject);
var
  a: integer; // valid types for each future values
  b: string;
  c: TForm;
  d: TImage;
begin

  // all values will be valid!  same that "nil"
  // but the "types" not necessary it's a type expected
  // a := b;
  // c := d;

  // mismatched types = incompatible types
  // [dcc32 Error] Unit1.pas(43): E2010 Incompatible types: 'integer' and 'string'
  // [dcc32 Error] Unit1.pas(44): E2010 Incompatible types: 'TForm' and 'TImage'

  // fortunatelly, the compiler look this! and dont compile code!
  // but in runtime avaliation, this it's not occurrs until the run it!
  // then, we have a "exception" raised! or in some cases, the bug appears
  // only in a "specific situations" not reproduced at all... = developer-bug!
  // sorry my english!

end;
----------
  // here, the Delphi power:  where a type is equal a another type,"IF" its "name" it's the same!
  // not necessarely, its value!

  //We can compare "name to type" as if it were the area of existence of a certain value!
  //That is, we are saying something like: Memory, "in this area here", you can only allocate spaces for this kind of values...

here, I'm not talking about "developer should take care about all possibilities in your code" no no no!
I'm talking about the "special situations" (like my test above), where the Delphi should take care my "errors idiot" ... you see?

of course, that my code should know many situations, but, in my proposital-tests, it should not pass! at all...

it's hard to xpress myself in another language... sorry!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/24 1:30:51
29楼: to @kentty

look this: Your code, my workaround!
MODE:  DEBUG or RELEASE! NO ERRORS ANYMORE!

----------

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Unit2;

procedure TForm1.Button1Click(Sender: TObject);
var
  F2: TForm2;
begin
  ShowMessage(integer(pointer(self)).ToString);

  if Assigned(F2) then
  begin
    ShowMessage(integer(pointer(F2)).ToString);
    F2.SayHello;       // 1
    F2.XXX := 'xxxxx'; // 2

    ShowMessage('F2.DataArray.Size=' + Length(F2.DataArray).ToString); // 3
    ShowMessage('F2.XXX=' + F2.XXX);          // 4
  end
  else
    ShowMessage('F2 Not exists');
end;

end.

----------
unit Unit2;

interface
....
type
  TForm = class(Vcl.Forms.TForm)  <== redefining the TForm class here!
  public
    procedure SayHello;
  end;

  TForm2 = class(TForm)
  private
    { Private declarations }
  public
    XXX      : string;
    DataArray: array [0 .. 100] of array [0 .. 100] of Integer;
    procedure SayHelloXXX;
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}
{ TForm2 }

procedure TForm2.SayHelloXXX;
begin
  ShowMessage('Hello from Form2 and XXX=' + XXX);
end;

{ TForm }

procedure TForm.SayHello;
begin
  ShowMessage('Hello from TForm and XXX=');
end;

end.

----------

NO ERRORS NOW!
The TForm class "now" have a method "SayHello" and "F2".SayHello now works!
because the TForm struture on memory have a new procedure "SayHello"!

按此在新窗口浏览图片
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/24 1:40:31
30楼: for that, always use "  F2:=nil;" on begin...
...

if 

TForm2...
 public
    procedure SayHello;

.... then a new address will be used to reference a "SayHello" re-introduced and your "old AccessViolation" go back!!!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/24 1:54:28
31楼:     TForm2($0040001).SayHello; /// WORKS!
    TForm2(266240).SayHello; /// WORKS!
    //
    TForm2($0040001).SayHelloXXX; // raise a AV! as expected!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/24 5:51:55
32楼: In Embarcadero's DocWiki, we can read the text that can prove my view that I tried to describe just above in my post:
----------
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Variables_(Delphi)

Variables (Delphi)
"A variable is an identifier whose value can change at run time.
Put differently, a variable is a name for a location in memory; 
you can use the name to read or write to the memory location.
Variables are like containers for data, and, because they are typed, 
they tell the compiler how to interpret the data they hold."
----------

Variables declared within a procedure or function are sometimes called local, while other variables are called global. Global variables can be initialized at the same time they are declared, using the syntax:

var identifier: type = constantExpression;

Local variables cannot be initialized in their declarations. Multiple variable declarations (such as var X, Y, Z: Real;) cannot include initializations, nor can declarations of variant and file-type variables.


- If you do not explicitly initialize a global variable, the compiler initializes it to 0.
- Object instance data (fields) are also initialized to 0. 
- On the Win32 platform, the contents of a local variable are undefined until a value is assigned to them. <---


When you declare a variable, you are allocating memory which is freed automatically when the variable is no longer used. In particular, local variables exist only until the program exits from the function or procedure in which they are declared. For more information about variables and memory management, see Memory Management.

You can create a new variable that resides at the same address as another variable. 
To do so, put the directive absolute after the type name in the declaration of the new variable, 
followed by the name of an existing (previously declared) variable.

You can create dynamic variables by calling the GetMem or New procedure.
Such variables are allocated on the heap and are not managed automatically.
Once you create one, it is your responsibility ultimately to free the variable's memory;
use FreeMem to destroy variables created by GetMem and Dispose to destroy variables created by New.
Other standard routines that operate on dynamic variables include ReallocMem, AllocMem, Initialize, Finalize, StrAlloc, and StrDispose.

Long strings, wide strings, dynamic arrays, variants, and interfaces are also heap-allocated dynamic variables,
but their memory is managed automatically.


Thread-local (or thread) variables are used in multithreaded applications.
A thread-local variable is like a global variable, except that each thread of execution gets its own private copy of the variable,
which cannot be accessed from other threads.
Thread-local variables are declared with threadvar instead of var. 

You can free a variant by setting it to Unassigned and an interface or dynamic array by setting it to nil.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2022/6/24 6:41:17
33楼: Sample by Embarcadero:


procedure TForm1.Button1Click(Sender: TObject);
var
  P: Pointer;
begin
  // here my test to see if "P" have or not a value in runtime...
  Caption := integer(P).ToString;
  //
  P := nil;
  if Assigned(P) then
    MessageDlg('You won''t see this', mtInformation, [mbOK], 0);
  //
  GetMem(P, 1024);  { P valid }
  FreeMem(P, 1024); { P no longer valid and still not nil }
  //
  // P := nil;  // uncomment and the P = "0"
  if Assigned(P) then
    MessageDlg('You''ll see this', mtInformation, [mbOK], 0);
  //
  // here let's test if "P" have or not a value in runtime...
  Caption := Caption + ', ' + integer(P).ToString + ' ... on the end of all';
end;

result := YES, the value  (not necessarely the same value)  will be present same than "nil" is assigned again on var!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/6/24 7:30:00
34楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2022/6/24 8:59:46
35楼: 都是脚本语言惯出来的毛病
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v2.1 版权所有 页面执行29.29688毫秒 RSS