发现DELPHI编译器一个严重的错误

sztony 2012-04-30 09:19:18
加精
无意中发现DELPHI编译器一个很严重的错误:

如下:

我先定义一个数组类型:

type
tmyarr = array of char;


然后定义过程:

procedure test(const arr:tmyarr);
begin
arr[1] := 'X';
end;

然后在一个过程中调用该函数:

var
A :TMYARR ;
begin
SETLENGTH(A,3);
A[0] := 'A';
A[1] := 'B';
A[2] := 'C';

TEST(A);

FORM1.CAPTION := STRING(A);
end;

不知道大家看出问题没有?
就是过程test的参数为CONST,也就说,常量参数在过程内应该不能修改,但DELPHI却可以通过编译,并且结果显示,确实修改了常量参数内容!

为了证实它是否错误,我又用LAZARUS(FREE PASCAL)编译,编译结果不能通过,提示不能给一个常量赋值。

可见,在DELPHI中,编译器确实有错误。





...全文
7066 211 打赏 收藏 转发到动态 举报
写回复
用AI写文章
211 条回复
切换为时间正序
请发表友善的回复…
发表回复
hzg134679hzg 2014-07-30
  • 打赏
  • 举报
回复
一晃又过了几年了,不知楼上的哥们还有多少在坚持DELPHI。 不知多少年没有碰DELPHI了啊。 匆匆过了一下,争得很好玩,现在想想,也觉得没有意思,DelphiGuy这个小伙子为什么不去写个编译器呢,看似很懂的样子,却没见到bcc32源码,作为程序员,源码才是王道也是最后解释。
  • 打赏
  • 举报
回复
[Quote=引用 208 楼 的回复:]

c里的const指针分3种情况(见"C Primer Plus"(第五版)12.7.1):
const float * pf; //pf 指向一个常量浮点数值, 但pf本身的值可以变,可以指向另一个const值
float * const pf; //指向的地址不能变,但所指向的值可以变
const float * const pf;//pf本身和pf指向的值都不能变
[/Quote]
你这个说的有点不对题了,声明一个指针的变/常量和传递指针参数不一样,函数指针参数是按值传递的,所以指针实参会被复制,你在函数体里移不移动指针对实参没有任何影响,float* const pf这种参数没有任何意义,你见过这样的函数参数么?
  • 打赏
  • 举报
回复
[Quote=引用 207 楼 的回复:]

206楼的链接看了,说的比较明白了,这不是BUG

最后一个回复又有一个链接:http://rvelthuis.de/articles/articles-openarr.html
"Open array parameters and array of const"
[/Quote]

所谓“说的比较明白了”,那个帖子里Andreas Hausladen认为不是BUG只是他的个人观点,而且他的解释没有说服力,就是所谓的“const 指针理论”,这个解释已经被证伪了(见55楼)。
另外,他的解释中还有明显的错误,“Check3() uses a const open (parameter) array. Open arrays are incompatible to the other two array variants.”这显然是错的,开放数组是兼容其他两种数组(动态数组和静态数组)的,而不是不兼容,Delphi帮助中关于open array parameter部分有明确的说明。
看那山瞧那水 2012-05-16
  • 打赏
  • 举报
回复
c里的const指针分3种情况(见"C Primer Plus"(第五版)12.7.1):
const float * pf; //pf 指向一个常量浮点数值, 但pf本身的值可以变,可以指向另一个const值
float * const pf; //指向的地址不能变,但所指向的值可以变
const float * const pf;//pf本身和pf指向的值都不能变
看那山瞧那水 2012-05-16
  • 打赏
  • 举报
回复
206楼的链接看了,说的比较明白了,这不是BUG

最后一个回复又有一个链接:http://rvelthuis.de/articles/articles-openarr.html
"Open array parameters and array of const"
proer9988 2012-05-15
  • 打赏
  • 举报
回复
当楼主对DELPHI再熟悉多点, 就会知道是自己的问题了.
DELPHI的数据类型跟C++的不一样的, 假如直接把C++的处理方式放到DELPHI来处理特殊的数据类型, 这个是大有问题的. DELPHI为了兼容COM, ACTIVEX等的东西, 做了非常多的手脚, 不清楚的话, 的确有麻烦, 但不能否定这些东西给一般的编程人员带来不少方便.
还是一句, 学习多点吧, 别半桶水就发表名言
====================================================
还是上面的这位兄弟说的好!关于这个问题,有位兄弟已经指出来了,看这里的讨论:https://forums.embarcadero.com/message.jspa?messageID=454172

顺便,即使你研究的深入些,也别一副居高临下的口气--不是做学问的品质!
=====================================
  • 打赏
  • 举报
回复
200多楼了,d版还有这么热闹的时候,不易啊。
好久不用d了,记得在d中传递数组实际也是传递的一个指针,如果是这样的话,那lz的理解是对的,这应该是d的一个bug,当然也可能是pascal语言历史以来就是这样,这咱就不了解了。但在c语言中这肯定是错误的,像下面这种函数参数

void func( const char* psz );

const实际是修饰的psz所指向的内容而非psz本身,因为修饰psz这个指针没有任何意义,他在func局部被复制入栈,在func函数里不管你如何移动psz指针,都不会影响原始传入的实参,这也是为什么可以将指向const对象的指针指向非const对象,而不能将指向非const对象的指针指向const对象。const指针参数总是保护指针指向的值而非指针本身。

关于函数参数,我个人理解,只有2种传递方式,值参或引用参,值参总是在函数局部被复制,指针属于值参,而引用参总是在函数局部被绑定而不进行复制,也没有内存地址,通过寄存器传递。
hello170cm 2012-05-14
  • 打赏
  • 举报
回复
虽然说智者千虑必有一失,
但是很明显,这次是楼主理解有问题
  • 打赏
  • 举报
回复
油猴!大忽悠Seamour怎么不出来忽悠了?

你忽悠来忽悠去,彻底把自己忽悠爆炸了。“delphi 的帮助文件意义不大,本来质量就不怎么样”(157楼)这话真是太经典了!对你来说确实如此,否则你怎么能喷出“无修饰就是按值传,var 修饰传引用。按什么传有用的是有没有 var 修饰,你他妈拿一个“动态数组参数”有个鸡巴毛用?”(198楼)这种妙论呢???

言归正传,我前面说过你什么来着,“你这种人,基本功不够、概念不清,还自视甚高、目高于顶,不知道你的自信来自于哪里?狂妄无知?这么多年,你连参数的引用语义和值语义的基本概念都没搞明白,就跳出来夸夸其谈,说错了也没关系,但是得认哪,可你倒好,梗着脖子硬犟,实在狡辩不过去了,就自造概念、振振有词:我没错...我是那啥意思...你水平弱理解不上去...笔误...”,没说错你吧,你就是连参数的引用语义和值语义的基本概念都没搞明白。望加强学习。:)
ron_xin 2012-05-12
  • 打赏
  • 举报
回复
鼓掌,看得云里雾里
  • 打赏
  • 举报
回复
改正200楼的一个错误:

传值、传引用是对实参->变参的传递而言的
===================================
传值、传引用是对实参->形参的传递而言的
Seamour 2012-05-11
  • 打赏
  • 举报
回复
最后还是给不懂的人补充一段内容,看客们别光看鞋底被脸打的热闹。
179楼讲的方式其实我前面也给了,只不过形式没写成那样而已。现在再用 @ 的方式给一遍,有兴趣的可以去做实验:

type TDynArr = array of Integer;

procedure foo1(a: array of Integer);
begin
Pointer((@a)^) := nil;
end;

procedure foo2(var a: array of Integer);
begin
Pointer((@a)^) := nil;
end;

procedure foo3(a: TDynArr);
begin
Pointer((@a)^) := nil;
end;

procedure foo4(var a: TDynArr);
begin
Pointer((@a)^) := nil;
end;

procedure bar;
var
a: TDynArr;
begin
SetLength(a, 1);
a[0] := 1;
foo1(a); // Length(a)=1, a[0]=1
foo2(a); // Length(a)=1, a[0]=0
a[0] := 1;
foo3(a); // Length(a)=1, a[0]=1
foo4(a); // a=nil
end;


动态数组变量实际上是一个指针,类似的还有:string 实际上是一个指针,类类型实际上是一个指针,对象实际上是一个指针,interface 实际上是一个指针。这意味着,只要能够理解它们的实现并且清楚自己的代码在做什么,完全可以用指针来完成这些类型语义上的操作,并且与这些类型的变量之间想起相互传递使用。下面再来一段代码演示如何使用指针完成动态数组的工作:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
FastMM4, SysUtils;

type
TDynArr = array of Integer;

function CreateDynArr(Len: Integer; InitVal: Integer): Pointer;
var
parr: PIntegerArray;
i: Integer;
begin
GetMem(parr, SizeOf(Integer)*(Len+2));
parr[0] := 1; // set the RefCnt to 1
parr[1] := Len; // set the Length to Len
for i:=2 to Len+1 do
parr[i] := InitVal; // initialize elements' value, set each to InitVal
Result := @parr[2]; // move its pointer to point at the end of array header
end;

procedure ShowArr(ArrPtr: Pointer);
var
parr: PIntegerArray;
i, len: Integer;
s: string;
begin
parr := ArrPtr;
i := 0;
len := parr[i-1]; // get the length
s := Format('Length: %d, RefCnt: %d', [len, parr[i-2]]); // get the reference count
Write(s, 'Elements = ');

s := Format('[%d', [parr[0]]); // get each value of the elements
for i:=1 to len-1 do
s := Format('%s, %d', [s, parr[i]]);
Writeln(s, ']');
end;

procedure ChangeDynArr(var X: TDynArr);
var
p: PPointer;
begin
X := nil; // decrease X's RefCnt, and release the dynamic array if RefCnt=0
p := @x;
p^ := CreateDynArr(5, 100);
end;

procedure main;
var
x: TDynArr;
p: Pointer;
px, pp: PPointer;
begin
SetLength(x, 2);
ShowArr(x);

p := x;
pp := @p;
px := @x;
Writeln(Format('[Pointer] size=%d, value=%p, addr=%p', [SizeOf(p), pp^, pp]));
Writeln(Format('[TDynArr] size=%d, value=%p, addr=%p', [SizeOf(x), px^, px]));

ChangeDynArr(x);
ShowArr(x);
Writeln(Format('[Pointer] size=%d, value=%p, addr=%p', [SizeOf(p), pp^, pp]));
Writeln(Format('[TDynArr] size=%d, value=%p, addr=%p', [SizeOf(x), px^, px]));
end;

begin
main;
Readln
end.

首先在 main 过程中,动态数组变量 x 在栈上占用一个指针的空间(SizeOf(TDynArr)=SizeOf(Pointer)),并且能够在赋值语句的右侧把值传给指针类型变量(p:=x),并且赋值后两者的值相同(p=x;pp^=px^);在 ChangeDynArr 后,可以看到 x 的指针值发生了变化。
ShowArr 的参数是一个指针,在传参的时候按值传递实参,即把 x 本身的指针值复制给 ArrPtr,和局部变量 p=x 的过程相同。然后完全使用指针显示它的引用计数、长度及各元素的值。
ChangeDynArr 按引用传参,即把 x 的地址传给 ChangeDynArr,清零后用指针的方式把从 CreateDynArr 得到的值赋给它。CreateDynArr 完全使用指针在堆上建立了一个 TDynArr 的数组数据,然后返回这个指针值。
这段代码在32位 delphi 中正常工作,并且 FastMM 会验证并没有内存泄露,从而印证我上面关于动态数组实际上就是一个指针的说法。64位由于引用计数和长度使用了 Int64,所以这个代码无法正确使用。用 NativeInt 虽然在 XE2 上能做到32位与64位兼容,但由于2010之前的版本又没有 NativeInt 类型,所以无法做到和老版本兼容。估计这里还是用老版本的人多,于是就没有写成 XE2 上32位、64位都能正常的方式,还是选择了兼容老版本。
Seamour 2012-05-11
  • 打赏
  • 举报
回复
[Quote=引用 194 楼 的回复:]
对照一下Delphi中动态数组的特性,你看看动态数组参数是引用语义还是值语义?其实不必废话,帮助中都明说了“Delphi对动态数组没有实现值语义”。
[/Quote]
你tm无视 delphi 的文档里的明确定义么?
Most parameters are either value parameters (the default) or variable (var) parameters. Value parameters are passed by value, while variable parameters are passed by reference.

无修饰就是按值传,var 修饰传引用。按什么传有用的是有没有 var 修饰,你他妈拿一个“动态数组参数”有个鸡巴毛用?

Since the Delphi language does not implement value semantics for dynamic arrays, "value" parameters in routines do not represent a full copy of the dynamic array.

你丫看不懂 value semantics 是 for dynamic arrays 还是 for parameters of dynamic arrays 么?后面 "value" parameters 才讲的是无修饰的传值,况且后面还有 despite Value being a by-value parameter 印证这一说法。而且“值”参数 not represent “a full copy”又被你选择性的无视了。“不代表一个完整拷贝”,自然暗示着还是有拷贝的,只不过这个拷贝不是对动态数组的一个全复制。如果写文档的年代已经有引用类型和浅复制的说法,这句话就不会写成现在这个样子,a full copy 用今天的话讲就是深复制。不知道是谁无视这两段文字,拿着 implement value semantics for dynamic arrays 半截子话当作救命稻草,文档给出 parameters 的地方有明确定义你丫无视,没带 parameters 的地方还硬往上套。
到了你那可好,干脆就成了:因为不是值类型,所以传值就是传引用,于是根本没有任何值的复制了。按照你的逻辑,很容易推论出 DelphiGuy is not represented as a full shit = DelphiGuy is not represented as a single piece of shit。翻译过来,你丫不完全像屎=你完全不像屎,后者就是你看到这句话后理解的意思吧?你可以自豪的说:DelphiGuy's brain doesn't have a full block of the shit in his own head,于是就找到一个大家都能接受的方式说你脑子里完全没有屎(而不是没有完全被屎堵住)——我举双手赞成这句话。
本来很简单的一句话,自己在那强词夺理,绕啊绕啊的,句子都读不明白还装B。
我从一开始就说了,动态数组是引用类型;delphi 文档也说了,var 修饰叫传引用。“引用类型”和“传引用”俩东西根本就不是一回事儿,动态数组是什么语义跟传参数有个毛关系,还他妈硬要往一起扯,你丫就一傻B。

还要继续玩儿文本打自己脸么?
前面没回你关于文档是因为我机器上没帮助文件,懒得弄而已,别真以为玩儿文档我会虚你。


我本以为爱贴帮助文档的人应该具有基本的理论素质,知道哪些文本是可以引用、哪些是不行的。我前天想过从 C++ 标准文档里找东西扇你脸的,无奈文档中没有给出定义,于是也就算了。然后打算从 C++ Prime 里找一段,后来一瞅书,就凭你连引用类型、传引用都分不清的智商,肯定理解不了 lvalue/rvalue——跟笨蛋解释一个更复杂的概念肯定吃力不讨好,于是只好又算了。不过你就不一样了,既然敢瞅了眼百度百科就出来装,那么随便搜个不知道哪家啥水平的 FAQ 就拿它当宝贝自然也就不奇怪了。咱不能上百度百科找东西把自己降到一个极低水平的层次上,更何况在这种层次上你更有经验,咱肯定打不过你。
从一开始我就明确讲了值类型、引用类型,传值、传引用。脑子里都是屎分不清引用类型和传引用,后来说不过了赶紧整出来半拉“引用语义”来死扛的人不是我。


你要是觉得继续死鸭子嘴硬就能撑住,那你就继续玩儿吧。有的人从头到尾的在概念的使用范围和解释上都没变过,对看起来不利于自己的文档也作出了解释;有的人概念变来变去,从文本上好不容易抓住半根稻草后,或者断章取义或者对其它文本选择性失明。我回的贴子里有大量的示例,也问了你大量的问题。你一句代码都没贴过,也没正面回答过一个问题,一直揪着那半句话不放。

我的贴子是从懂汇编的人的能理解的深度讲起的,到后面已经浅到不懂指针应该也能看明白的层次了。等到了190楼讲出来的内容,我相信就算一开始还弄不明白这些东西的人也完全能看得出来,现在是谁在露怯了。都不是瞎子,你丫就继续得意去吧,我不奉陪了。你要觉得“他还在被我打”的话,那我的鞋底的确还在被你的脸打,go on。
  • 打赏
  • 举报
回复
[Quote=引用 198 楼 的回复:]

你tm无视 delphi 的文档里的明确定义么?
Most parameters are either value parameters (the default) or variable (var) parameters. Value parameters are passed by value, while variable parameters are passed by reference.

无修饰就是按值传,var 修饰传引用。按什么传有用的是有没有 var 修饰,你他妈拿一个“动态数组参数”有个鸡巴毛用?
[/Quote]

大家快来看傻子哟,Seamour这傻子连这么基本的英文也理解不了,还不学无术、自以为是(帮助对这棒槌确实作用不大,因为他半懂不懂、其实不懂,半通不通、其实不通,七窍通了六窍、还是不通),这傻子看不懂人家写的是“大多数参数是值参或者变参之一”,这意思可不是说“参数不是值参就是变参”(并非就这两类),而且人家根本就没说“值参一定传值”,这傻子就自鸣得意地整出个“无修饰就是按值传”!你傻得都透腔冒泡了。

看看对你帮助不大的帮助中是怎么写的:
Parameter passing

Variable (var) parameters are always passed by reference, as 32-bit pointers that point to the actual storage location.

Value and constant (const) parameters are passed by value or by reference, depending on the type and size of the parameter:

...
A long-string or dynamic-array parameter is passed as a 32-bit pointer to the dynamic memory block allocated for the long string. The value nil is passed for an empty long string.

谁告诉你的“无修饰就是按值传”???抽你这个不学无术还嚣张的傻子一个大嘴巴,以后长点记性!
你看看动态数组参数是按什么传的?是值还是引用?(你这傻子千万别再说“隐含指针的值就是动态数组的值,所以动态数组传值”这类蠢话)


[Quote=引用 198 楼 的回复:]
Since the Delphi language does not implement value semantics for dynamic arrays, "value" parameters in routines do not represent a full copy of the dynamic array.

你丫看不懂 value semantics 是 for dynamic arrays 还是 for parameters of dynamic arrays 么?后面 "value" parameters 才讲的是无修饰的传值,况且后面还有 despite Value being a by-value parameter 印证这一说法。而且“值”参数 not represent “a full copy”又被你选择性的无视了。“不代表一个完整拷贝”,自然暗示着还是有拷贝的,只不过这个拷贝不是对动态数组的一个全复制。如果写文档的年代已经有引用类型和浅复制的说法,这句话就不会写成现在这个样子,a full copy 用今天的话讲就是深复制。不知道是谁无视这两段文字,拿着 implement value semantics for dynamic arrays 半截子话当作救命稻草,文档给出 parameters 的地方有明确定义你丫无视,没带 parameters 的地方还硬往上套。
[/Quote]

哇哈哈哈哈... 大家看好了这傻子卖弄的嘴脸,在这傻子的“逻辑”里,Delphi对动态数组没有实现值语义,对动态数组参数还能实现值语义!

Seamour这傻子你还敢喷“"value" parameters 才讲的是无修饰的传值”?你这傻子一直没搞明白,(形式上的)值参不一定传值,也可能传引用。

我就花点时间教育你一些基本概念,免得你以后瞎忽悠露出红屁股:
值语义、引用语义的概念范畴最大,不仅适用于参数,适用于一切有赋值操作的情况。
传值、传引用是对实参->变参的传递而言的,值参、变参是指形参的类型,变参肯定是传入(以下省略“入”)引用,但传引用的参数不一定都是变参,而值参则不一定传值,也可能传引用,取决于参数的类型和大小。之所以叫“值参”是因为在语言发展的最初阶段,这种类型的参数确实是传值的,但是随着语言的复杂化,类型的增加,为了使用的方便或者优化性能,值参形式的声明也不一定传值了,所以现在有些值参类型,只是声明形式上看起来是值参,其实已经是引用语义,而不是值语义。懂了吗?:)

Seamour 2012-05-10
  • 打赏
  • 举报
回复
最后再以不懂的人写一段。
如果去了解一下 Java、C# 的话,值类型、引用类型、按值传递、按引用传递都是非常明确的概念。对于引用类型,Java/C# 还有两个明确的概念,叫做浅复制(shallow copy)和深复制(deep copy)。
delphi 的帮助文档基本上成形于90年代,那个时候浅复制和深复制的概念还没什么人提。delphi 文档中对动态数组参数那一段的描述(Array parameters)如果用浅复制、深复制来讲的话,只需要两句话就能让人明白了。以下是全部原文:
When you declare routines that take array parameters, you cannot include index type specifiers in the parameter declarations. That is, the declaration

procedure Sort(A: array[1..10] of Integer); // syntax error

causes a compilation error. But

type TDigits = array[1..10] of Integer;
procedure Sort(A: TDigits);

is valid.Another approach is to use open array parameters.

Since the Delphi language does not implement value semantics for dynamic arrays, "value" parameters in routines do not represent a full copy of the dynamic array. In this example

type
TDynamicArray = array of Integer;

procedure p(Value: TDynamicArray);
begin
Value[0] := 1;
end;

procedure Run;
var
a: TDynamicArray;
begin
SetLength(a, 1);
a[0] := 0;
p(a);

Writeln(a[0]); // Prints "1"!
end;

Note that the assignment to Value[0] in routine p will modify the content of dynamic array of the caller, despite Value being a by-value parameter. If a full copy of the dynamic array is required, use the Copy standard procedure to create a value copy of the dynamic array.

这一大段用 Java/C# 的语言来说:动态数组参数只进行浅复制,不进行深复制。
借用前面这些概念,delphi 里的动态数组是一个引用类型,它的含义是:如果在栈上声明一个动态数组变量,那么栈中只保存一个指针,它的数组数据在堆上分配,栈上的指针只是对堆上数据的一个引用。深/浅复制只用在相同引用类型的复制上,值类型(参考我 blog 里的其它文)不适用。当对动态数组进行浅复制(dest:=source)时,源变量实际上是一个指针,目标变量实际上也是一个指针,浅复制只是简单的复制指针的值,复制后源变量和目标变量指向堆上的同一块数据。而深复制(dest:=Copy(source))是说,在堆上分配一块新的空间,把源变量引用的数组数据的值一一复制到这块新空间中,然后使目标变量引用这块新数据,复制后源变量和目标变量指向堆上不同的数据块。动态数组参数只对实参进行一个浅复制,也就是说,它只在被调用函数的栈帧中复制一个指针,而不会把堆上的数组元素一一复制到栈空间中。
相比之下,如果参数是静态数组的话,无修饰的传参会进行“深复制”,把源数组的数组一一复制到被调用函数的栈帧当中。事实上静态数组不是引用类型,所以深复制/浅复制的概念不适用,这也是我加引号的原因。

对于开放数组,读过我的 blog 的人会知道它的行为和静态数组参数非常像,不带修饰符时会对实参进行一次“深复制”。事实上它不适用深/浅复制的说法,同理还是因为只针对引用类型,静态数组不是引用类型,但它能够作为开放数组的实参,所以不适用。对于动态数组实参同样也不适用,因为深复制只能对源变量类型和目标变量都是引用类型、且类型相同时才有效的说法,像 var p: Pointer; p:=@arr[0] 这种形式没办法用深/浅复制来定义。换句话说,虽然 p 和 arr 实际上都是指针,指向的也是相同的数据块,但编译器采用完全不同的方式对待,它们的行为也完全不同。比如说,能够对 arr 进行 SetLength,但是 SetLength 不适用于 p。同理,虽然表面上看起来,无修饰的开放数组参数不但一一复制了动态数组实参的元素,而且也会获得一个指向新数据块的指针,但编译器并不把它当作动态数组对待。比如说,没法对它进行 param:=nil 或者 SetLength 的操作。

该说的都说完了,希望各位看客能有所收获,而不是很无脑、纯 happy 的光看个热闹。
proer9988 2012-05-10
  • 打赏
  • 举报
回复
楼上分析的精辟!赞一个!
frtrnr 2012-05-10
  • 打赏
  • 举报
回复
呵呵,有点掉书袋了,这个问题,大概比方韩大战中的“的地得”问题还要小~~~~~~~~~~~
Q315054403 2012-05-10
  • 打赏
  • 举报
回复
做学术,值得折腾。。值得争吵
做项目或任务,就绕过
  • 打赏
  • 举报
回复
[Quote=引用 193 楼 的回复:]

楼上的还真以为自己比BORLAND还厉害,呵呵
[/Quote]

这话你得去对Seamour说,虽然BORLAND的文档中明确说了“Delphi对动态数组没有实现值语义”,他还是一再出来喷“动态数组传值”,狡辩不过去了,就把“传值”解释成“传隐含指针的值”,他居然“创造性”地把动态数组的“值”理解成那个编译器维护的隐含指针的“值”!还煞有介事地整出一个pointer的例子来比较,真是脸皮厚的赛过城墙拐角了。
  • 打赏
  • 举报
回复
Seamour,你既然敢喷出“值类型引用类型、按值传参按引用传参又不是 delphi 独有的概念或者我自创的,那么多语言都有这概念,我有必要跟你这种水平的人玩文字游戏么?你丫自己脑子一锅屎,分不明类型和传参,然后就跟我扯“引用语义”这个神奇的、能够混淆引用类型、按引用传递两者区别的你独创的概念。”这种无知的笑料(189楼),那就让你看看所谓“引用语义”、“值语义”是什么概念,在其他语言中的解释,这是关于C++的:
http://www.parashift.com/c++-faq-lite/value-vs-ref-semantics.html
What is value and/or reference semantics, and which is best in C++?

With reference semantics, assignment is a pointer-copy (i.e., a reference). Value (or "copy") semantics mean assignment copies the value, not just the pointer.

这个你还看得懂吧,对于引用语义,赋值是指针拷贝(比如一个引用),值语义意味着赋值复制值(本身),不只是指针。

对照一下Delphi中动态数组的特性,你看看动态数组参数是引用语义还是值语义?其实不必废话,帮助中都明说了“Delphi对动态数组没有实现值语义”。

你概念不清的最大问题就在于,象我前面说过的:
你所谓的“动态数组传值”实际是指传那个“隐含指针”的值,不是参数类型(动态数组)的值,属于你的自造概念,此“隐含指针”不等同于实际类型(隐含指针是reference to 实际类型的数据),只是编译器暗中维护的一个东西,因为动态数组变量是一个“隐含指针”就把动态数组参数当成指针来解释,那你实在是“水平弱理解不上去”啊。
加载更多回复(177)
《深入核心——VCL架构剖析》光盘说明-、光盘用途 本光盘为《深入核心——VCL架构剖析》一书的配套光盘,供读者阅读图书时参考和学习。二、光盘内容 光盘“源代码”目录中包含了书中所有源代码,文件目录和图书的目录相对应。如“Chap01”表示书中第1章的范例源代码。 光盘包含了全部的pas、dfm和dpr文件。 我们已经对所有文件进行了简体化工作。如果您在使用中发现有界面乱码问题,请将窗体Font改为“宋体”,Charset改为gb2312即可,并请即时告知我们,让更多读者受益。三、运行环境 多数代码可以直接在Delphi6和Delphi7环境下运行。部分涉及.NET技术内容的代码,需要在Delphi 7上安装Borland .NET Complier for Delphi编译器方可编译执行。Borland已经正式推出Delphi 8 for .NET,所以本书范例中部分内容可能与D8最终版本不符。四、使用方法 直接将范例文件拷贝至硬盘适当目录即可。 多数完整应用程序代码已经编译为.exe可执行文件,读者可直接运行之。五、防病毒 本光盘所有文件都已经过Norton Antivirus扫描,未发现有任何已知病毒。六、风险 读者须对使用光盘所附代码、文件所造成的一切后果负责。 七、如果对代码有任何疑问、建议或者发现有遗漏、错误之处请与 liwei@csdn.net联系。六、所有源代码可以在学习和工作中直接使用,但请不要用于商业目的。

16,749

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧