C 언어에서 swap 에 대한 질문입니다..

등짝을보자의 이미지

과거 turbo c 에서..

temp = *a;
*a = *b;
*b = temp;

이래야만 값이 변한다고 이해하고 있었습니다..근데...
gcc 에서...

temp = a;
a = b;
b = temp;

이렇게 했더니 값이 변하더군요?
어떤 차이인가요??

turbo C는 c89로 알고있는데..gcc 는 몇인가요?

litdream의 이미지

C 에서는 기본적으로 pass by value 만 따르기 때문에, swap() 이라는 별도의 func를 만드셨을경우, pointer 를 넘기지 않는다면 본래값이 바뀌지 않겠죠?

삽질의 대마왕...

삽질의 대마왕...

Necromancer의 이미지

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

Necromancer의 이미지

temp = a;
a = b;
b = temp;

코드내에 직접 썼다면 바뀌는게 정상입니다. turbo c도 마찬가지고요.
하지만 별도함수로 분리한다면 함수 리턴시에 바꾼 값이 다 사라지기 때문에
처음 말한 포인터로 처리를 해줘야죠.

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

익명사용자의 이미지

포인터 스왑에 대한 질문이 아닌가 생각되는군요..
값이 바뀌기야 하죠...주소값하고 통째로..

simpid의 이미지

죄송하지만 C 언어에 대해 다시 공부하셔야 할 것 같습니다.

변수와 포인터 변수의 차이점을 모르시는군요.

그리고 참고로
a ^= b;
b ^= a;
a ^= b;
의 코드로도 swap이 됩니다.
temp를 안써도 된다는 장점이 있죠.

winner의 이미지

우선 위 방법은 ^= 가 = 보다 빠르다는 가정에서 제시된 방법이라고 생각됩니다.
하지만 그것이 과연 참인지는 알 수 없고요.

Bit 연산은 무부호정수형에서만 보장이 됩니다.

하지만 암호학수업 때 위의 과정이 암호화, 복호화과정에 쓰이는 것을 보고 정말 놀랬던 것이 기억납니다.

gcc 는 version 에 따라 다르지만 C99 을 많이 지원하고 있습니다.
최신의 4.1 version 의 표준지원확인은
http://gcc.gnu.org/gcc-4.1/c99status.html 에서 볼 수 있습니다.

전웅의 이미지

a ^= b;
b ^= a;
a ^= b;
 
a -= b;
b -= a;
a -= b;
 
a ^= b ^= a ^= b;
 
a -= b -= a -= b;

와 같은 부류의 "임시 변수 쓰지 않고" 두 값을 바꾸는 위험하고 쓸모 없는
트릭은 대체 몇십년이 지나야 보지 않게될지 모르겠습니다.

비유로 "임시 변수 없이" 두 값 swap 하기는 "망치 없이" 못 박기라고
부르고 있습니다.

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

winner의 이미지

그런데 값 bits 를 모두 온전히 보존하기 위해서는 분명히 임시변수가 필요하겠습니다만
연산과정의 값들이 주어진 data 형에 의해서 표현될 수 있다면 잘못되었다고만 말할 수는 없지 않을까요?

물론 swap 은 자주 쓰이고, 대부분 주어진 요구사항이 data 형이 동일한 두 값을 서로 바꿔준다정도이겠지만...
위의 과정에서 기본적으로 깔고 있는 과정이 주어진 사항에 맞다면 꼭 틀렸다고 할 수 없겠지요.

그리고 unsigned 형들도 ^= 치환은 불가능한 것인가요?

전웅의 이미지

> 그런데 값 bits 를 모두 온전히 보존하기 위해서는 분명히 임시변수가 필요하겠습니다만
> 연산과정의 값들이 주어진 data 형에 의해서 표현될 수 있다면 잘못되었다고만 말할 수는 없지 않을까요?
>
> 물론 swap 은 자주 쓰이고, 대부분 주어진 요구사항이 data 형이 동일한 두 값을 서로 바꿔준다정도이겠지만...
> 위의 과정에서 기본적으로 깔고 있는 과정이 주어진 사항에 맞다면 꼭 틀렸다고 할 수 없겠지요.
>
> 그리고 unsigned 형들도 ^= 치환은 불가능한 것인가요?
>

하나의 수식으로 swap 과정을 합쳐놓은 것들은 아예 논외로 하겠습니다.
sequence point 와 관련된 규칙을 위반했을 뿐더러 때문에 실제 오작동하는
사례도 있습니다.

임시 변수를 도입하지 않고 위와 같은 tricky 한 방법을 사용한다면 분명
뭔가를 얻기 위해서 일겁니다. 아무런 설명 없이 저 코드만을 주었을 때
swap 을 위한 코드라는 것을 단번에 깨닫기 어렵다는 사실은 그만큼 저
코드의 가독성이 떨어진다는 의미이므로 그에 상응하는 이득이 없고서야
저런 코드를 쓸 이유가 없습니다.

일단, 가장 큰 이유 중 하나는 임시 변수를 쓰지 않는다는 점입니다. 일반
적인 경우에는 이것이 의미가 없지만 매크로를 구성할 때는 중요한 이득이
될 수 있습니다. namespace 지원이 미약한 C 언어로서는 표준 위반이나
사용자 namespace 를 침범하지 않고 사용할 수 있는 명칭을 얻어낼 수
없습니다. 하지만, 위와 같은 방식을 통해서는 임시 변수 명칭에 대한
고민 없이 swap 매크로를 구성할 수 있기에 아주 매력적으로 보입니다.
하지만,

int func(int *p, int *q);
{
   ...
   SWAP(*p, *q);
   ...
}
 
func(&i, &i);

와 같이 실행된다면 어떤 결과가 발생할까요?

또 종종 지적되는 문제 중 하나가 ^= 트릭의 경우 정수형 (그것도 full
portability 를 위해서는 무부호 정수형) 에만 적용할 수 있는 트릭이라는
것입니다. 물론, -= 를 사용하면 부동형까지 확장할 수 있으나, 부동형이
실수를 저장하는 것이 아니라 근사값만을 저장하는 것이고 연산 과정에서
도입될 수 있는 반올림 오차를 고려한다면 진정 두 값을 "맞바꾼다"고 보기
어렵습니다. 예를 들어, 매우 큰 값과 매우 작은 값을 -= 트릭으로
맞바꾸는 경우를 생각해볼 수 있습니다 (결과로 나오는 값은 심하게 왜곡
될 수 있습니다).

해당 트릭을 사용하는 다른 이유로는 종종 성능 문제를 듭니다. 임시 변수
를 사용하는 것보다는 빠르다는 주장입니다. 하지만, 늘 그렇듯이 성능과
관련된 문제는 "일반적"이며 "절대적"인 정답이 없으며, 정말 swap 기능이
프로그램의 전체적 성능에 치명적인 영향을 미치고 있는지를 확인하기 전에
무조건적으로 가독성 및 안전성을 포기한 트릭을 도입하는 것이 결코
바람직해 보이지는 않습니다.

단순히 상황, 가정, 목적에만 부합한다는 이유만으로 왜 사용해야만 하는지
에 대한 정당성 없이 무엇인가를 희생해야 하는 트릭을 도입할 수 있다면,
무슨 트릭인들 못 사용하겠습니까?

임시 변수 없이 swap 하기에 대한 트릭은 C FAQs 에서도 다룰만큼 오래된
내용입니다. 그 긴 시간동안 여러번 제기되었지만 단한번도 다른 것을
희생할 만큼 "유용"하다는 결론이 난 적이 없는 방법입니다.
개인적으로도 앞으로는 좀 안 만났으면 하는 바람입니다.

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

winner의 이미지

그런데 동일변수 swap 문제는 생각해 보지 못했던 문제군요.
당황했습니다.
C FAQs 를 말하셔서 찾아 다시 읽어보니 이해에 도움이 되네요.

그런데 망치없이 못박기라... 최근에 cable TV 에서 자주 방영한 '싸움의 기술'이 떠오르네요. ^_^

최근 들어 매우 바쁘신 생활을 하시는 것으로 아는데 답변 감사드립니다.

사실 저 또한 필요성을 못 느껴 쓰지 않는 관용구인데 물어봐서 번거롭게 한 것 같아 죄송합니다.

전웅의 이미지

제가 좋아서 단 답변입니다 winner 님께서 죄송해 하실
필요 전혀 없습니다. ^^

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.