View Full Version : متغیر ثابت یا ...
Zahed2008
سه شنبه 20 اسفند 1387, 16:03 عصر
سلام، من یه تابعی نوشتم که ورودی اون یه ثابت از نوع رکورد هستش. وقتی اونو در داخل تابع تو یه متغیر شبیه خودش می ریزم و دستکاری می کنم، خود متغیر ثابت هم تغییر می کنه(!؟) :متفکر:
مگه ورودی ثابت نیست؟ پس چرا تغییر می کنه ؟ مثل حالت زیر:
Tdata = record
x: array of double;
y:array of double;
end;
...
function solve( const data0: Tdata ): Tdata;
var data1 : Tdata;
begin
data1 := data0;
...
حالا اگه این ورودی ثابت(data0) رو تک تک با حلقه for بریزم. تغییر نمی کنه. به نظر شما چرا این طوری می شه؟ :اشتباه:
for i:= 1 to length(data0.x)-1 do
data1[i].x := data0[i].x;
...
vcldeveloper
سه شنبه 20 اسفند 1387, 17:09 عصر
نوع فیلدهایی که برای رکورد استفاده می کنید، فیلدهای عادی نیستند. شما دارید از Dynamic Array برای X و Y استفاده می کنید. Dynamic Arrayها همیشه بصورت by reference منتقل میشند. در حالی که داده های ساده و رکرودها بصورت by value منتقل میشند.
الان در کد شما، Data0 بصورت یک رکورد روی stack قرار داره. Data0 دو تا فیلد آرایه پویا داره، که بصورت دو Pointer روی stack قرار دارند، اما داده های واقعی آرایه روی Heap قرار دارند، و این pointerها به خانه اول آرایه بر روی Heap اشاره می کنند.
حالا اگر به عناصر آرایه دسترسی پیدا کنید، و آنها را تغییر بدید، دارید مستقیما خانه های حافظه موجود در Heap را تغییر میدید.
بطور کلی، اشیاء، Interface ها، stringها، و Dynamic Arrayها همیشه بصورت by reference به توابع منتقل میشند، حتی اگر مستقیما آنها را بصورت var تعریف نکنید. برای stringها و Dynamic Arrayها می تونید آنها را مستقیما بصورت const به تابع منتقل کنید، که در اون صورت بصورت by value منتقل میشند. یعنی اگر در کد بالا داشتید:
type
TMyArray = array of double;
function Foo(const AnArray: TMyArray);
َAnArray بصورت ثابت منتقل میشد، و نمی تونستید عناصر آن را تغییر بدید.
AliReza Vafakhah
سه شنبه 20 اسفند 1387, 19:53 عصر
type
TMyArray = array of double;
function Foo(const AnArray: TMyArray);
َAnArray بصورت ثابت منتقل میشد، و نمی تونستید عناصر آن را تغییر بدید.
آقای کشاورز میشه توضیح بدید چرا پارامترAnArray قبلش به صورت type تعریف کردید.(آیا به خاطر تفاوت بین ByRef,ByVal )
ببخشید میشه درمورد پارامترهای Interface توضیح بدید
vcldeveloper
چهارشنبه 21 اسفند 1387, 02:31 صبح
میشه توضیح بدید چرا پارامترAnArray قبلش به صورت type تعریف کردید.(آیا به خاطر تفاوت بین ByRef,ByVal )
نه، دلیل خاصی نداشت. اینطوری فقط واضح تر هست.
ببخشید میشه درمورد پارامترهای Interface توضیح بدید
منظور پارامتری هست که نوع Interface را به تابع منتقل کنه. در باره نوع Interface در دلفی قبلا توضیح دادم. یک مقاله هم در این زمینه در مجله برنامه نویس منتشر شده.
Zahed2008
چهارشنبه 21 اسفند 1387, 09:43 صبح
سلام، ممنون از آقای کشاورز،
من دقیقاً کاری که گفتید رو انجام دادم ولی بازم تغییر می کنه. شاید من درست متوجه نشدم:
type Tvv = array of Double;
...
function solve( const vv0: Tvv): Tvv;
var vv1: Tvv;
begin
vv1 := vv0;
...
end;
...
vv3 := solve( vv2);
و در اینجا vv2 به همراه vv3 تغییر می کنه ؟؟!! :متفکر:
vcldeveloper
چهارشنبه 21 اسفند 1387, 12:50 عصر
من دقیقاً کاری که گفتید رو انجام دادم ولی بازم تغییر می کنه.
من تصور می کردم که بخاطر ماهیت مشابه Dynamic Arrays و Strings، دلفی با هر دو به شکل مشابهی برخورد میکنه، اما ظاهرا اینطور نیست. یعنی:
نوع داده Dynamic Array همیشه بصورت by reference منتقل میشه، اما نوع داده string اگر بصورت پارامتر const تعریف بشه، بصورت by value، و در غیر اینصورت، بصورت by reference منتقل میشه.
در کدهای زیر، تفاوت استفاده از string بصورت ثابت، و Dynamic Array بصورت ثابت مشخص میشه:
function solve(vv0: Tvv): Tvv;
begin
Result := vv0;
end;
Unit3.pas.30: begin
0046C6A1 64FF30 push dword ptr fs:[eax]
0046C6A4 648920 mov fs:[eax],esp
Unit3.pas.36: Result := vv0;
0046C6A7 8BC6 mov eax,esi
0046C6A9 8BD3 mov edx,ebx
0046C6AB 8B0D70C64600 mov ecx,[$0046c670]
0046C6B1 E8169EF9FF call @DynArrayAsg
Unit3.pas.37: end;
0046C6B6 33C0 xor eax,eax
0046C6B8 5A pop edx
0046C6B9 59 pop ecx
0046C6BA 59 pop ecx
0046C6BB 648910 mov fs:[eax],edx
0046C6BE 68CBC64600 push $0046c6cb
0046C6C3 C3 ret
0046C6C4 E9177DF9FF jmp @HandleFinally
0046C6C9 EBF8 jmp $0046c6c3
0046C6CB 5E pop esi
0046C6CC 5B pop ebx
0046C6CD 5D pop ebp
0046C6CE C3 ret
واضح هست که کامپایلر یک بلوک try-finally مخفی برای reference-counting ایجاد کرده.
function Test(str: string): string;
begin
result := str;
end;
Unit3.pas.40: begin
0046C6D0 53 push ebx
0046C6D1 56 push esi
0046C6D2 8BF2 mov esi,edx
0046C6D4 8BD8 mov ebx,eax
Unit3.pas.42: result := str;
0046C6D6 8BC6 mov eax,esi
0046C6D8 8BD3 mov edx,ebx
0046C6DA E8718DF9FF call @UStrAsg
Unit3.pas.43: end;
0046C6DF 5E pop esi
0046C6E0 5B pop ebx
0046C6E1 C3 ret
کامپایلر بلوک مخفی try-finally را ایجاد نکرده. اگر بجای انتقال string بصورت const، آن را بصورت معمولی یا var منتقل می کردیم، کدی مشابه کد تولید شده برای تابع Solve تولید می شد.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.