[C언어] 이런 문법 ... 보신 적 있으신 분 ..

naddolki의 이미지

int main(void)
{
for (;;)
{
int yy;
}

return 0;
}

C 에서 위와 같은 문법이 유효하네요 ;;

물론, 함수가 아니더라도 ..
어느 블럭이든 .. scope 가 .. { 블럭 } 내부로 한정되는 .. 지역변수를 가질 수 있습니다 ..

즉,

int main(void)
{ // #0

int xx; // scope : #0 ~ #0'

{ // #1
int yy; // scope : #1 ~ #1'
} // #1'

if(1)
{ // #2
int xx; // scope : #2 ~ #2'
} // #2'

return 0;
} // #0'

또한, java 나 c++ 에서 ..

for(int yy = 0; y < 10 ; y++)
{
// ...
}

와 같이 .. 선언해도 마찬가지로 yy 는 for(){ ... } 내부에서만 사용이 가능한 일회성 변수입니다 .

근데 ...

for()문 { 블럭 } 내부에 있는 선언문은 이해가 안 됩니다 .
매번 루프를 둘면서 { 블럭 } 내부의 내용을 수행하는데 ...
그러한 곳에 선언문이 있다면 ...
매 루프 때마다 같은 이름의 변수를 생성하게 되고 ... 이름 중복으로 오류가 나야하지 않나요 ?

snowall의 이미지

블럭 안에서 선언된 변수는 말씀하신대로 1회성 변수이므로 블럭이 끝나면 사라지겠죠. 그리고 다시 처음부터 반복.

--------------------------
피할 수 있을때 즐겨라!
http://snowall.tistory.com

피할 수 있을때 즐겨라! http://melotopia.net/b

naddolki의 이미지

블럭이 끝나면 사라진다는 말씀은 ..
"블럭을 벗어날 때 소멸" 된다는 말씀이시겠지요 ?

제 질문의 의도를 잘못 파악하신 것 같은데요 ..

첫 loop 을 돌고나서 .. loop 조건이 true 이어 ..
다시 loop 를 돌게 된다면 ...

블럭에 다다르긴 했지만, 조건이 true 이어 블럭을 벗어나지는 않았으니 ... yy 는 ..
사라지지 않은 상태이겠지요 ?

그렇게 두 번째 loop 를 돌게 되고 ..
블럭 내부에 있는 int yy = 0; 을 또 한번 만나게 되겠지요 ?

0으로 초기화 된 yy 라는 변수를 선언하라 ... 는 의미이지요 ?

근데, 이미 yy 라는 변수는 첫번 째 loop 에 의해 .. 존재하는 상황이지요 ?

그럼 ... 변수명이 중복되겠지요 ?

그럼에도 .. 컴파일 시엔 에러가 나지 않는데 어떻게 가능하느냐는 거지요 .

물론, 선언문이 최초로 한 번만 수행되고 ...

두 번 이상의 loop 이 이루어질 땐 .. 선언문이 무시되는 '문법' 이 당초부터 .. C 에 있었던 거라면 ..
모르겠지만 ...
그런 문법을 들어 본 적이 없기에 ...

제목을 "이런 문법 보신 적 있으신 분 .." 이라고 했던 겁니다 .

설연희 입니다 ^ ㅡ^ㅋ

ymir의 이미지

새로운 scope 를 가진다는 것은 그 이전에 선언된 변수와는 전혀 무관하다는 뜻입니다.

int a; // global variable;
 
int main(void)
{
  int a; // local variable
 
  while (1)
  {
    int a;  // another local variable for while loop only
  }
 
  return 0;
}

위의 세 변수는 모두 다른 값, 다른 scope 를 갖고 있으며..
각각의 scope 에서 상위의 scope 에 해당하는 변수들은 아무런 영향을 미치지 않습니다.

변수명이 중복된다는 것은 코딩하는 프로그래머 입장에서 보는 관점이지..
컴터 입장에서는 서로 다른 세개의 변수라고 보는게 타당합니다.

block 안쪽의 새로운 선언문은 block 이 끝나는 순간 해제되기 때문에..
다시 loop 를 돌더라도, 다시 선언되는것에는 아무런 영향을 미치지 않습니다.

block 안쪽의 내용들을 잘라서 새로운 inline function 으로 만든것과 비슷하다고 보시면 이해하시기 쉬울듯 합니다.

근데, 이미 yy 라는 변수는 첫번 째 loop 에 의해 .. 존재하는 상황이지요 ?
 => block 이 끝나는 순간, block 안쪽에 선언된 변수도 사라집니다.
    loop 를 돌때마다 새로 선언되고, 초기화 또는 할당된다는 뜻입니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

mithrandir의 이미지

그런걸 scope라고 합니다. 블럭 내부에 선언된 변수는 scope, 즉 가시영역이 그 블럭으로 한정되죠.
선언은 실제로 무언가를 '수행'하는 과정과는 좀 다릅니다.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

naddolki의 이미지

자문자답입니다만 .. 곰곰히 생각해 보니 ..

for(;;)
{
int yy;
}

가 가능할 것도 같네요 .

그래서 .. 결과적인 차원에선 .. mithrandir 님의 말씀에 일정 부분 동의합니다 .

다만 .. "선언과 수행은 다르다" 고 하셨는데 .. 왜 다르다고 생각하시는지에 대한 ..
말씀은 없으셔서 .. 어떻게 이끌어낸 결론인진 모르겠습니다만 ..

아마 제 생각과는 .. 다른 쪽으로 .. 생각해서 .. 이끌어 낸 결론이 아니실까 ...
하고 생각해 봅니다 .

제가 내린 결론에 대해 ...
(추측이긴 하지만 ..) 제가 알고 있는 범위 내에서 .. 설명해 보겠습니다 ..

storage class 에는 life time (수명) 과 scope (가시 영역)이 있는데 ..
변수의 scope 는 해당 변수의 선언 위치에 의존적인 반면 ..
(물론, life time 이 끝나지 않은 상황이라면, 다른 블록에서도 포인터로 접근은 가능합니다)
변수의 life time 은 scope 와는 별개로 다뤄집니다 .

따라서, 생성/소멸과 관련 있는 life time 은 .. scope 와 별개로 취급이 되므로 ..

for()의 블럭 내부에 위치한 int yy; 는 ...
scope 가 for() 블럭 내부임을 알리는 것이고 ...
loop 조건이 true 이어 .. 다음 루프에서 또다시 yy 의 scope 를 알리더라도 ...
error 가 발생할 이유는 없습니다 .

한편 int yy; 의 life time 은 ..
scope 와 달리 ...

for() 블럭에 처음 진입할 때 stack 에 push 되어 .. 빠져나갈 때까지 유지됩니다 ..

따라서, for() loop 을 돌면서 ...
거듭 만나게 되는 int yy; 선언문은 .. scope 를 알리는 일만 되풀이할 뿐 ..
변수 생성을 반복하진 않습니다 .

scope 와 life time 이 별개로 다뤄진다는 것을 확인하기 좋은 예로 ...
가령, 내부 정적인 변수를... 가진 ..
함수 func() 를 두 번 이상 호출하는 경우가 있습니다 .

void func()
{
static int si = 0;
si++;
}

void main(void)
{
func();
func();
}

static 변수의 scope 는 .. func() 블럭 내부이지만 ..
static 변수의 life time 은 ... 프로그램이 시작될 때부터 종료하는 시점까지입니다 .

그런 고로, static 변수가 선언된 블록에 진입하지 않더라도 ..
static 변수는 프로그램이 시작 시점부터 이미 메모리에 존재합니다 .
또한, 이는 끝날 때까지 지속되기 때문에 ...
위의 예에서와 같이 .. 호출한 func() 의 수행이 끝나더라도 .. si 는 소멸되지 않습니다 .

같은 이유에서 ... scope 를 벗어난 func() 의 외부에서도 언제든지 ..
포인터를 이용해 si 에 접근이 가능한 거죠 .

만약 .. 그렇지 않고 ..
static int si = 0; 이 "stack 에 공간을 할당하라는 의미 (life time 의 시작을 알리는 의미)" 이었더라면 ..
func() 가 호출될 때마다 생성되고, 종료될 때마다 소멸되겠지요 .

또한, "data 영역에 변수를 생성하라는 의미" 이었더라면 ..
func() 를 두 번째 호출할 때부턴 .. 중복 error 가 날 테구요 .

결국 .. error 도, 생성과 소멸의 반복도 ... 없는 이유는 ..
life time 과 scope 가 다르기 때문입니다 .
정확히는 scope 가 변수의 선언 위치에 의존적인 반면 ..
life time 은 꼭 그렇지는 않다는 겁니다 .

설연희 입니다 ^ ㅡ^ㅋ

planetarium의 이미지

static 변수에 대해서는 말씀하신게 맞습니다만...

for문 같은 블록의 경우에는
블록이 반복될 때에, 처음으로 돌아가는 순간에
"블록이 끝나고 다시 시작한다" 고 생각하시는게 맞을것 같습니다.
윗분들도 그런 의미로 설명하신 거구요. 윗분들 설명에서 "블록이 안 끝나고 처음으로 돌아가는 경우" 는 없습니다.

static과 같지 않다는 것을 보여주는 간단한 예:

for (i=0; i<5; i++)
{
int a=0;
printf("%d\n", a++);
}
obbaya의 이미지

생각을 전개해 나가시는 방법이 줗네요.

C에 한정해서 똘끼님의 결론를 지지합니다~

msvc나 gcc가 만들어내는 asm코드로 추론완성을.

jick의 이미지

제가 보기엔 별로 좋은 방법이 아닌 것 같습니다. 이렇게 표준에 답이 나와있는 문제를 이해하는 유일한 방법은 표준을 제대로 설명한 문서를 읽어보는 것입니다.

(물론 "표준은 이렇지만 실제로 많이 사용되는 컴파일러 x y z에서는 이러이러하게 표준과 다른 동작을 한다"라는 경우도 있긴 한데, 그건 일단 표준을 이해한 상태에서 다시 들여다봐야 할 문제고...)

C라는 언어의 특성상, 많이 사용되는 컴파일러에서 내 코드가 에러를 안 내고 돌았다고 한들, 내 코드가 에러 없는 올바는 코드라는 보장은 전혀 없습니다. 제대로 이해 못한 상태에서 이런 "시행착오"로 문법이나 라이브러리를 익힐 경우, 나중에 시스템이나 컴파일러 버전만 올라가도 잘돌던(?) 코드가 뻗어서 거품을 무는 상황을 만나게 됩니다.

planetarium의 이미지

MS Visual C++ 6.0 에서

void func()
{
for(int yy = 0; y < 10 ; y++)
{
// ...
}
for(int yy = 0; y < 10 ; y++)
{
// ...
}
}

이게 이름 중복으로 에러가 나는 버그가 있었죠 아마...
snowall님 말씀대로 블록이 닫히는 순간 사라진다고 보는게 맞습니다.

neocoin의 이미지

c99 이전에는 저 문법이 허용되지 않았습니다. See Also'for' loop initial declaration used outside C99 mode - Cppsyntax

VC++ 6 이 c99과 C++ 스펙이 완료되기 이전에 구현되었기 때문에 저 법을 허용하게 되었었죠.

그러니까 name scope 이 { } 로 시작하고 끝나기 때문에, for 내의 선언에 대해서는 상위 namescope 에 포함되다고 생각해서 MS는 구현해 놓은 것 같더라구요.

어떻게 보면 저 상태에서 가장 모호하지 않은 구현 상태가 아닐까 생각합니다.;;

planetarium의 이미지

음... 그렇군요. VC++ 6.0의 나이를 미처 생각을 못했네요... 감사합니다.

kaeri17의 이미지

Visual C++은 C++컴파일러죠. C99나오기 전부터 C++표준에는 저 문법이 허용되었던 것으로 압니다.

neocoin의 이미지

Visual C++ 6이 등장할때 공식적인 C++ 스팩이 완료되지 않은 상태였습니다.

찾아보니 C++ 최초의 스팩이 완료는 98년인데, Visual C++6 이 같은해에 나왔습니다.

그래서 해당 문법이 구현되었지만, 그때까지 모호한 구현에 대해서는 MS가 알아서 했다는 표현을 했습니다.

yae1021의 이미지

생각보다 흔하게 사용되는 문법입니다.(적어도 저는 그렇네요)
duff's device의 경우는 상당히 독특한 {}의 사용으로 엄청난 일을 해내죠.

ifree의 이미지

class Test
{
public:
Test(){cout << "Hello" << endl;}
~Test(){cout << "Bye" << endl;}
};

int main()
{
for(int i = 0; i < 10; ++i)
{
Test test;
}

return 0;
}

result:
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye
Hello
Bye

mac040의 이미지

GDB로 TRACE해보세요.

doraq의 이미지

class Test
{
	public:
		Test(){cout << "Hello" << endl;}
		~Test(){cout << "Bye" << endl;}
};
 
int main()
{
	for(int i = 0; i < 10; ++i)
	{
		Test test;
	}
 
	return 0;
}

아..되는군요

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.