Google 그룹스는 더 이상 새로운 유즈넷 게시물 또는 구독을 지원하지 않습니다. 과거의 콘텐츠는 계속 볼 수 있습니다.

"결합방향"에 대한 재질문,,,ㅜ.ㅜ

조회수 4회
읽지 않은 첫 메시지로 건너뛰기

Luis Ahn

읽지 않음,
2003. 5. 13. 오전 11:47:0903. 5. 13.
받는사람
int *func1(){
int *pi;
pi = malloc(sizeof(int));
puts("func1");

return pi;
}
int func2(){
puts("func2");

return 10;
}
int main(void)
{
*func1() = func2(); // 여기

return 0;
}

위 코드의 주석부분에서 실제 func1()가 먼저 호출 될지 func2()가 먼저 호출될지
표준이 정의하지 않는다는 것이 맞나요?
A = B 라는 수식이 있을때, A와 B의 평가는 implementation이 정의하고 그 결과에
대해 결합방향의 정의대로 B의 값을 A에 대입하는 건지요?
"결합방향"이라는 게 자꾸 애매해 지네요...

다시 말하지만,,,"결합방향"이라는 것은 수식의 평가를 implementation이
정의하고 그 결과에 대해서 "결합방향"의 원칙에 따라 연산을 하는 것인지요?

-------------------------------------------------------
From Luis Ahn.
I can do everything through Him who gives me strength!!
Philippians 4 :13
-------------------------------------------------------

김승범

읽지 않음,
2003. 5. 13. 오후 8:29:0003. 5. 13.
받는사람
Luis Ahn wrote:
>
> *func1() = func2(); // 여기
>
> 위 코드의 주석부분에서 실제 func1()가 먼저 호출 될지 func2()가 먼저 호출될지
> 표준이 정의하지 않는다는 것이 맞나요?

그렇습니다.

> A = B 라는 수식이 있을때, A와 B의 평가는 implementation이 정의하고 그 결과에
> 대해 결합방향의 정의대로 B의 값을 A에 대입하는 건지요?
> "결합방향"이라는 게 자꾸 애매해 지네요...

이전에 말씀드렸듯이, 연산자가 하나일 때는 결합 방향이 의미가 없습니다.
대입 연산자의 결합 방향이 '오른쪽에서 왼쪽으로'라는 것은 A=B=C라는
수식이 (A=B)=C가 아닌 A=(B=C)로 해석된다는 것이지, 대입의 방향이
A←B라는 것과는 상관이 없습니다.

>
> 다시 말하지만,,,"결합방향"이라는 것은 수식의 평가를 implementation이
> 정의하고 그 결과에 대해서 "결합방향"의 원칙에 따라 연산을 하는 것인지요?

결합 방향은 우선 순위가 같은 연산자가 나열될 때 괄호를 어떻게 치느냐의
문제라고 생각하시면 됩니다.

--
김승범

Jun Woong

읽지 않음,
2003. 5. 14. 오전 10:40:1003. 5. 14.
받는사람
"Luis Ahn" <lui...@mtis.co.kr> wrote in message news:b9r41i$f69$1...@news.hananet.net...

> int *func1(){
> int *pi;
> pi = malloc(sizeof(int));
> puts("func1");
>
> return pi;
> }
> int func2(){
> puts("func2");
>
> return 10;
> }
> int main(void)
> {
> *func1() = func2(); // 여기
>
> return 0;
> }
>
> 위 코드의 주석부분에서 실제 func1()가 먼저 호출 될지 func2()가 먼저 호출될지
> 표준이 정의하지 않는다는 것이 맞나요?

맞습니다.

> A = B 라는 수식이 있을때, A와 B의 평가는 implementation이 정의하고 그 결과에
> 대해 결합방향의 정의대로 B의 값을 A에 대입하는 건지요?
> "결합방향"이라는 게 자꾸 애매해 지네요...

결합방향은 같은 우선순위의 연산자가 2개 이상 "직접" 관련되지 않은 상황
에서는 아예 문제가 되지 않습니다.

*a() = b();

이 식에서 관련된 연산자는

- 함수 호출 연산자 () 2개
- 간접 지정 연산자 *
- 대입 연산자 =

이며, 두 번 나온 () 가 서로 (피연산자를 공유하며) 직접 관련된 경우가
아닙니다. 같은 우선순위의 연산자가 직접 관련되어 나오는 경우 결합방향
이 정의되어 있지 않으면 프로그래밍 언어가 아닌 일반적인 수학에서도 그
의미가 달라질 수 있습니다 - 아래 두 수식은 분명 그 의미가 다릅니다.

(10 - 5) - 7
10 - (5 - 7)

그리고, 수학에서는 아무 문제를 일으키지 않는 상황에서도 프로그래밍 언
어에서는 문제가 되는 경우도 있습니다. (IT 백두대간 C 언어, p.744)

>
> 다시 말하지만,,,"결합방향"이라는 것은 수식의 평가를 implementation이
> 정의하고 그 결과에 대해서 "결합방향"의 원칙에 따라 연산을 하는 것인지요?
>

우선순위는 서로 다른 두 연산자 중 어느 것의 의미가 먼저 수식에 적용되
는지를, 결합방향은 연속하여 적용되는 두 연산자가 같은 우선순위를 가지
고 있는 경우 어느 연산자의 의미가 먼저 적용되는지를 기술하는 방법일 뿐
이며, 각 피연산자를 평가하고 실제 side effect 를 일으키는 순서는
implementation 이 임의로 정할 수 있습니다. 즉,

int *f(), g(); // 적절한 초기화 가정
*f() + g();

이 수식에서 우선순위는 위의 수식이 *(f() + g()) 가 아닌 (*f()) + b 의
의미로 해석됨을 나타내는 것일 뿐, f() 가 g() 보다 먼저 평가되어 호출된
다는 의미를 나타내는 것은 아닙니다. 또한,

int f(), g(), h();
f() - g() - h();

이 수식에서 결합방향은 위의 수식이 f() - (g() - h()) 가 아닌
(f() - g()) - h() 의 의미로 해석됨을 나타내는 것일 뿐, 피연산자로 주어
진 부분 수식 f(), g(), h() 중 어느 것이 먼저 호출되다는 의미를 나타내
는 것은 아닙니다. 제가 책에서도 강조해듯이, 우선순위와 결합방향은 온전
한 수식을 평가하는 "부분적인" 순서만을 기술하며, (해당 수식을 평가하는
데 필요한 과정인) 피연산자나 부분 수식을 평가하고 관련된 side effect
를 일으키는 순서는 표준이 정의하지 않습니다. 물론, 그러한 순서를 표준
이 본질적으로 정의할 수 없는 것은 아닙니다 - || 혹은 && 같은 연산자가
그 예외에 해당합니다. 하지만, 각기 다른 상황에 처할 수 잇는
implementation 에게 모든 연산자의 피연산자 평가 순서 혹은 side effect
발생 순서를 요구하는 것은 C 언어로 만들어진 프로그램을 매우 비효율적인
것으로 만들어 버릴 수 있기에 그러지 않는 것 뿐입니다. 즉, 결론적으로

i++ + i++

같은 수식의 결과를 표준이 잘 정의해 줄 수도 있었겠지만 성능을 심각하게
희생해가며 그럴만한 가치를 못 느끼기에 그러지 않는 것 뿐입니다 - 이식
성을 고려하는 의미있는 프로그램이 위와 같은 수식을 과거에 사용하지도
않았을 뿐더러 앞으로도 사용할 이유가 없다는 관점입니다. 반면, 우선순위
와 결합방향은 반드시 표준에 의해 적절하게 정의되어야 의미있는 프로그램
이 표준을 따르는 모든 implementation 에서 올바른 행동을 보장받을 수 있
습니다. 성능을 위해서 다음 수식의 결과가 implementation 마다 달라질 수
있도록 허락하는 것은 아무래도...

f() * g() / h()


[이어지는 이야기는 관련된 것이지만 다소 다른 성격의 문제를 다룹니다]
참고로, 피연산자나 부분 수식을 평가하는 순서가 반드시 해당 수식과 관련
된 side effect 의 발생 순서와 어떤 연관을 갖어야 하는 것은 아닙니다.
즉,

(a = 10) + 16

이라는 수식에서 a = 10 을 평가해 대입 연산자의 결과로 10 을 얻어내는
(피연산자로 주어진) 부분수식의 평가가 실제 a 라 이름 붙여진 대상체에
결과 값인 10 을 저장하는 side effect 를 동시에 수반할 필요는 없다는 뜻
입니다. (IT 백두대간 C 언어, p.756)

단, 대입 연산자의 경우 한가지 중요한 순서가 보장됩니다.
(IT 백두대간 C 언어, p.756, p.762)

r = f();

r 에 우측 피연산자의 결과를 대입하는 side effect 는 f() 의 평가 (호출)
이후에 이루어져야만 합니다 - 대입할 값을 모르는데 실제 대입이 이루어질
수는 없겠지요. 이를 "chain rule" 이라고 부릅니다. 물론, 바로 위에서 설
명했듯이 대입 연산자의 좌우측 피연산자 "사이"의 평가 순서는 이와 같은
side effect 와 무관하기 때문에,

*f() = g();

chain rule 이 g() 가 f() 보다 먼저 호출됨을 보장해 주는 것은 아닙니다.
다만, (*f()) 로 지정되는 대상체에 g() 의 호출 결과를 저장하는 행위가
반드시 g() 호출 (완전한 평가) 이후에 이루어질 수 밖에 없다는 뜻입니다.
유사한 논리를 통해,

a = b = a = 0;
a = a = 0;

같은 수식 모두가 정의되지 않은 잘못된 수식입니다.
(IT 백두대간 C 언어, p.762)


다소 어려운 이야기를 하나 꺼내자면 a[i] = a[a[i]]; 같은 수식은 위에서
설명한 chain rule (과 공식적인 표준의 규칙) 에 의해 정의된 행동을 보장
받지만, a[a[i]] = 1; 와 같은 수식은 표준의 명시적인 규칙을 적용할 경우
sequence point 규칙에 의해 정의되지 않는 행동을 갖는다는 것입니다. 하
지만 현실에서 실제 표준이 우려하는 문제가 발생할 여지가 없으며 실제 위
와 같은 수식을 정의되는 것으로 보는 것이 (표준의 명시적인 규칙과는 다
른) 위원회의 의도입니다 - 위와 같은 경우를 적절히 다룰 수 있는
sequence point 의 formal model 은 상당히 까다로운 문제이기 때문에 아직
도 위원회 내에서 진행 중인 것으로 알고 있습니다.

그럼...


--
Jun, Woong (myco...@hanmail.net)
Dept. of Physics, Univ. of Seoul
Web : http://c-expert.uos.ac.kr

Jun Woong

읽지 않음,
2003. 5. 14. 오전 10:45:0803. 5. 14.
받는사람
"Jun Woong" <myco...@hanmail.net> wrote in message news:b9tken$8pn$1...@news.hananet.net...
[...]

>
> int *f(), g(); // 적절한 초기화 가정

주석은 무시하시기 바랍니다. 중간에 예를 바꾸면서 주석을 지우지
않았습니다. :(

정덕기

읽지 않음,
2003. 5. 27. 오후 6:19:4803. 5. 27.
받는사람
w

"Luis Ahn" <lui...@mtis.co.kr> wrote in message
news:b9r41i$f69$1...@news.hananet.net...
새 메시지 0개