Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

10 views
Skip to first unread message

Luis Ahn

unread,
May 13, 2003, 11:47:09 AM5/13/03
to
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
-------------------------------------------------------

김승범

unread,
May 13, 2003, 8:29:00 PM5/13/03
to
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

unread,
May 14, 2003, 10:40:10 AM5/14/03
to
"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

unread,
May 14, 2003, 10:45:08 AM5/14/03
to
"Jun Woong" <myco...@hanmail.net> wrote in message news:b9tken$8pn$1...@news.hananet.net...
[...]

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

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

정덕기

unread,
May 27, 2003, 6:19:48 PM5/27/03
to
w

"Luis Ahn" <lui...@mtis.co.kr> wrote in message
news:b9r41i$f69$1...@news.hananet.net...
0 new messages