for문을 돌리던 중.. 아주 이상한 경우를 만났씀다....
제가 머에 홀린 건지..... 아님... 먼가 큰 실수를 하고... 허우대고 있는 건지....
좀 봐주시길....
-------- 이상하게 도는 포문의 예 ---------------
for j := 0 to 30 do
begin
MaxArray[j] := pfData[j];
MinArray[j] := PfData[j];
end;
for i:= 0 to rowCount - 1 do
begin
try
begin // Begin of Try
for j := 0 to 30 do // <- 이상항 부분.
begin // begin of For
If pfdata[i] > MaxArray[j] then
MaxArray[j] := pfData[i];
If pfData[i] < MinArray[j] then
MinArray[j] := pfData[i];
end; // end of For
AvgVal := AvgVal + pfData[i];
end // end of Try
except
result := False;
end; // end of Try Except;
end;
요걸 돌려 보믄... J 인자를 사용하는 포문이 두개가 있는데여....
위에 것은 잘 돌아 갑니다.... 근데 아래 안쪽 포문의 J 값을 Watch 해 보면.... -.-;; 31에서 시작합니다. 그러면서 downto 포문 돌아 가드시....
하나씩 줄더라구여..... 게다가 더 황당한건.... MaxArray나 minArray는 0에서 30번까지 할당된 어레인데.... MaxArray[31] (J가 31 부터 시작하는 이상한 짓을 하므로....)을 억세스 할텐데도.... 바이올레이션 에러가 않난다는 것이죠....
게다가.... 이게 거꾸로 도나 해서.... for문의 to를 downto로 바꿔보았더니....
^^ 그냥 않돌더라구여..... (않돌아야 정상이져.... 0에서 30으로는 내려갈 수 없으니까여.... -.-;;) 글구 아래 것도 좀 참조해 주세여.....
------------------- 잘 돌아가는 포문의 예 -------------------
요 아래 포문은.... 위에서 J 값 Watch가 먼가 이상해서..... 중간에서 j 값을 파일로 쓰게끔 해 본겁니다..... (중간에....Writeln(j)에서 써주는 거져...)
근데.... -.-;; 파일을 읽어 보니까.... 0-30까지 잘 돌았더라구여....T.T
먼가 이상해서.... 다시 J를 Watch 걸구 해보니까.....
중간에 WriteLn 있는 경우에는.... j가 0에서 30까지 잘 돌아 갑니다....
근데... 없는 경우에는 잘 않돌아 갑니다....
왜 그렇져?
AssignFile(F,'Texttt.txt');
Rewrite(f);
for i:= 0 to rowCount - 1 do
begin
try
begin
for j := 0 to 30 do
begin
writeln(f, intTostr(j));
If pfdata[i] > MaxArray[j] then
MaxArray[j] := pfData[i];
If pfData[i] < MinArray[j] then
MinArray[j] := pfData[i];
end;
AvgVal := AvgVal + pfData[i];
end
except
result := False;
end;
end;
CloseFile(f);
N 번반복해야 하는 코드는 어셈으로 다음과 같이 표현됩니다.
mov cx, N
repeat:
;어쩌구 저쩌구
dec dc
jnz repeat
즉 intel CPU에서 단순 반복문은 cx나 ecx를 이용하여 감소를 하면서 처리하면 속도가 빨라 집니다. 이는 컴파일러를 작성할 때 유명한 최적화방법중의 하나입니다.
이것에 델파이라는 컴파일러에서도 적용이 됩니다.
말씀하신 소스를 어셈블리로 분석해 보았는데 그 결과
31번을 돌기 위하여 count를 위하여 ecx라는 register를 사용하였고(위에서 설명된 바와 같이 초기값이 31이 됨) 이것이 마치 j라는 변수로 보여진 것 같습니다.
그리고 실제 pddata, MinArray, MaxArray라는 변수를 access하는 것은 범용 register가 사용되었었습니다.
즉 for j := 0 to 30 do.... 라고 했을 때
단순반복을 위해 ecx register에 31값이 들어 가고
배열변수의 포인터를 access하기 위해 eax, ebx, edx pointer가 먼저 초기화된다는 거죠.
델파이에서 마치 j라는 변수는 ecx인것처럼 보여진 것 갓군요.
실제 처리되는 것은 MaxArray[0], MinArray[0], pfdata[0]부터 처리됩니다.
쉽게 말해서 pseudo 어셈블리 코드로 풀어 쓴다면 다음과 같이 표현될 수 있습니다.
ecx := 31; // count만을 처리함
ebx := &pfdata[0]; // 시작포인터
eax := @MaxArray[0]; // 시작포인터
edx := @MinArray[0]; // 시작포인터
repeat:
If ebx^ > eax^ then
eax^ := ebx^;
If ebx^ < edx^ then
edx^:= ebx^;
inc(ebx);
inc(eax);
inc(edx);
dec(ecx)
jnz repeat
어떻게 보면 델파이의 버그라고 할 수도 있고
어떻게 보면 델파이 컴파일러 최적화의 단면이라고도 볼 수 있습니다.
이해가 되셨는지요... ^^