[완료]C언어 (우변)값에 대해서 개념적인 질문입니다.

loopbit@naver.com의 이미지

er

ifree의 이미지

우변값은 레지스터일 수도 있고,CPU 에 공급되는 명령어 스트림 상의 상수(immediate value)일 수도 있습니다.
즉 a = 3 의 대입문에서 상수 3은 레지스터나 메모리에 저장되지 않고
mov LValue 3 의 식으로 직접 명령어 세트가 작성되어 처리됩니다.

또 컴파일러가 좌변값을 레지스터로 쓰는 경우도도 있습니다.

좌변값은 그냥 값을 저장할 수 있는 장소, 우변값은 값을 표현할 수 있는 객체라고 보면되고, 대입식은 어셈블리에서 다음 둘 중의 하나로 표현됩니다.

mov register RValue
mov mem RValue

배열의 이름은 const pointer 로서, 그 값이 레지스터에 저장된다는 보장은 없고 일반적인 상수로 취급될 것 같네요.

익명 사용자의 이미지

Quote:
(상수는 메모리에 존재하지 않으므로).

메모리에 존재한다고 말할 수 있습니다.
명령어들과 그 argument들도 전부 어떻게든 메모리에 올라가야 합니다.

가령, 프로그램을 실행시키면, 해당 프로그램의 코드 영역이 전부 메모리에 올라간다고 할 수 있습니다.
즉, 저 상수도 메모리에 올라간다고 말할수도 있습니다.

상수는 저장 공간으로써 메모리에 올라와 있는것이 아니라는 표현이 "상수는 메모리에 존재하지 않다" 라는 표현보다 더 정확한 것 같습니다.

익명 사용자의 이미지

덧붙이자면, 상수는 개별적인 메모리 공간을 할당받아 메모리에 올라가지는 않지만,
명령어셋의 일부분으로써, 메모리에 올라간다고 할수 있습니다.

명령어도 메모리에 로드가 되므로, 명령어도 메모리에 존재한다라는것처럼요..

"메모리에 존재한다" 라는 표현의 의미를 좀 더 명확히 할 필요가 있는 의미였습니다.

loopbit@naver.com의 이미지

e

익명 사용자의 이미지

Quote:

int a;
a = 2 + 3;
이런 수식에서 우변값은 제가 알기로는 중앙처리장치(CPU)의 레지스터라는 메모리(memory)에 존재하는 것으로 알고 있습니다. 결국 이렇게 되면 좌변값은 주기억장치(RAM)에, 우변값은 레지스터(CPU)에 존재하는 값으로 본질적으로 구분되는 것으로 봐도 될까요? 그리고 레지스터의 메모리는 기본적으로 주소를 취득할 수 없는 것으로 알고 있습니다. 이런 식으로 이해하는 게 적합한지 궁금합니다.

제 생각으로는, 그런 식으로 이해하는게 부적합하다고 보여집니다.
a = 2 + 3 같은 수식과 문장은 C언어에서의 표현방식입니다.

이것을 언어학과 수학적인 표현에서의 접근으로 해석하고 이해해야지, 그것을 CPU와 machine-level 로 1:1 matching을 하듯이 생각하면 안됩니다.
프로그래밍 언어 표현 방식의 측면에서 봤을 때, 둘( Hardware와 C Programming Language ) 사이에는 어떠한 직접적인 연관성이 없습니다,

대학에서 언어학 개론 같은 수업을 들으시는것을 추천드립니다.
혹, 그런 수업을 들으시는 중 저런 생각을 하는것이라면, 방향을 잘못잡았다고 하고싶네요.
수학적표현과 언어학적 표현의 관점에 집중을 해보세요.

loopbit@naver.com의 이미지

그럼 원래 C언어가 하드웨어적인 지식을 몰라도 사용할 수 있게끔 고안된 거라는 뉘앙스 같네요.

어쨌든 혹시 개론 같은 책 좀 알려주실 수 있나요. 문법서 말고요. 학교를 다닐 수 있는 형편이 아니어서요.

jeongheumjo의 이미지

레지스터와 메모리를 구분해서 이해하기 위해서는 '컴퓨터 구조'를 공부해야 합니다. 혹은 '마이크로 프로세서' 나
이들 과목들은 전자,컴공과의 정규 전공과목입니다.
학교를 다닐 수 없으시다면 윤성우씨 책이 쉽고 논리적입니다.
윤성우씨의 C책, C++책, 윈도우즈 시스템 프로그램 책류 가 좋습니다.
뇌를 자극하는... (뇌자극)시리즈도 좋고요.
한빛미디어 출판사가 좋습니다.

시중에 아마 컴퓨터 구조나 프로그램 원리를 쉽게 설명하는 책이 있었던 것 같습니다.
뇌자극 시리즈 중에요. 그런 책들이 도움이 많이 될 것 같네요.
님의 지금과 같은 문제를 제대로 이해 못하면 그 이상 진도를 나가기 어려울 겁니다.
여러 책들을 통해 반드시 이해를 하셔야 할겁니다.

snowall의 이미지

어셈블러나 기계어 이외의, 중-고급 수준 프로그래밍 언어들은 추상화가 잘 되어 있어서 하드웨어를 직접 제어해야 하는 특수한 경우를 제외하면 하드웨어를 몰라도 됩니다. 메모리를 쓰고 싶으면 변수를 선언하면 되고, 연산장치를 쓰고 싶으면 연산자를 사용하면 되죠.

정규과정의 학교를 다닐 수 없다면 방송대 컴퓨터학과를 알아보시는 것도 좋습니다.

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

jeongheumjo의 이미지

a = 2 + 3
 
이런 수식에서 우변값은 제가 알기로는 중앙처리장치(CPU)의 레지스터라는 메모리(memory)에 존재하는 것으로 알고 있습니다.
 결국 이렇게 되면 좌변값은 주기억장치(RAM)에, 우변값은 레지스터(CPU)에 존재하는 값으로 본질적으로 구분되는 것으로 봐도 될까요?
 그리고 레지스터의 메모리는 기본적으로 주소를 취득할 수 없는 것으로 알고 있습니다. 이런 식으로 이해하는 게 적합한지 궁금합니다.

설명을 간단히 할 수 있는 질문이 아니군요... 서점에 당장 가서 컴퓨터 구조에 대한 쉬운 책을 찾아보셔야 할 것 같습니다..

loopbit@naver.com의 이미지

er

jeongheumjo의 이미지

int a[10];
a = 3; /* 오류 */
a[0] = 3;
*a = 3;

일단 배열 명칭은 수정할수있는좌변값이 아니기 때문에 첫 번째의 대입연산문은 오류일 겁니다.
제가 배운 바로는 배열명칭은 일단 거의 대부분의 문장에서 첫 번째 요소를 가리키는 포인터로 변환됩니다.
즉 우변값으로 변환되기 때문에 값에 값을 대입하는 것은 정의되지 않은 행동입니다.
==> 배열의 이름만 쓰면 그건 '그 배열의 첫 번지 메모리의 주소'이다 라고 공식처럼 외워야 합니다. <윤성우씨의 C 책 추천> 님이 이해하시는 것이 맞다고 볼 수 있겠습니다.

첫 번째 줄의 a가 어떤 문장에서 대입연산자의 오른쪽에 등장했을 때와 동등한 상황으로로 봐도 되는 거죠(p = a)?
한 마디로 a는 값이기 때문에 또 값은 레지스터에 존재하기 때문에 즉 대상체(object)가 아니기 때문에,
대입연산을 할 수가 없는 게 맞는 겁니까? 여기까지가 제가 오랜 시간 포인터와 배열을 공부하면서 내린 결론입니다.
==> 잘못 이해하시는 것 같습니다. 사실 님의 질문이 좀 이해가 안되는면이 있습니다. 하지만 이걸 이해하는데 레지스터를 고려할 필요는 없어보입니다. 메모리만 가지고 생각해도 될 수준의 문제같네요..
이 부분을 윤성우씨 스타일로 설명하면 변수는 3가지 속성을 가지는데 이름, 값, (가상메모리상의)주소 입니다.

int a[10];

라고 한다면 프로그래머는 변수 a 의 그림이 머릿속에 그려져야 하는데 그건 int 타입(4바이트)의 연속된 메모리공간(가상메모리상에서) 입니다.
.... 설명을 제대로 하고 싶어도 어렵네요... 책 찾아보시라는 말밖에 못하겠습니다.

결국 제가 제대로 배우고 있는 건지가 궁금합니다.
==> 포인터와 레지스터의 개념이 안잡히신 것 같습니다.

반드시 공부하셔야 할 내용은 컴퓨터 구조에서도 메모리 계층구조 입니다. 그리고 가상메모리까지요.. 그리고 C 언어의 포인터 부분...
이 부분의 개념이 전공자라도 이해 못하고 졸업하고 사회 생활하는 사람들도 많습니다.
게시판에서 제가 잘 설명을 할 수 있는 간단한 내용이 아니니 이 부분은 직접 시간을 내셔서 공부하셔야 할 것 같습니다.

winner의 이미지

slee0303님의 의견 참고하시고요.
제가 아는 책 중에 원하시는 내용을 포함하고 있는 것은 'C언어 펀더멘탈' 정도입니다. 문법이나 언어개론에는 포함되어 있다고 보기는 어렵고요.

제 생각에는 C를 완성하는데 hardware에 대한 지식은 필요한 것 같습니다. 물론 실재하는 어떤 hardware를 말하는 것은 아닙니다. 예를 들어 C언어의 정수형에 대해서 C 표준은 bit(2진)를 통한 부호화정수표현, 1의 보수표현, 2의 보수표현을 사용하는 hardware를 염두하고 작성되었습니다. 만일 3진법(3 state)이나, 10진법을 사용하는 hardware라면 표준의 수정이 필요할지도 모릅니다. 또한 memory 접근주소에 제한이 걸리는 일명 메모리정렬제한(memory alignment restriction) 같은 것도 결국 hardware에 의해 결정되는 것이니까요.

제가 생각하기에 C 표준은 이론적으로 hardware와 무관하게 programming language를 완성하는 형태로 C를 만든 것이 아니라 C의 목적에 맞게 이식성을 높이기 위해서 hareware 독립성을 높였습니다.

C99 rationale을 읽어보시는 것도 좋을 것 같네요.

C 표준을 공부하시는 분들이 C를 추상적으로 이해하라고 말씀하시는 것은 일반적으로 hardware가 이러니까 C는 이렇게 해야 한다라고 생각하는 방식이 너무 단편적인 이해로 멈추는 경향이 높기 때문입니다. 그리고 그렇게 작성된 code는 이식성이 떨어지기 마련입니다. C의 표준을 선도했던 사람들은 이해가 조금 어렵거나 까다롭다고 생각되는 사안에 대해서 C 표준에 맞춰 이식성을 떨어뜨리지 않는 모범적인 사례들을 보여주고는 하는데 그 차이를 알기 위해서는 다각도로 이해하는 방식을 추구해야 하기 때문이겠죠.

"상수는 memory에 존재하지 않는다."라는 글은 저도 봤는데 DRAM에는 없고, register에 있다라는 의미는 아닌 것 같습니다. 여기서 memory는 C 표준에서 정의한 추상적 단어이고, hardware로 그 memory를 구현하는 방식이 DRAM - register hardware memory 계층이겠죠. 제가 생각하기에 그 문장에서 memory라는 것은 C 표준에서 이야기하는 object들이 저장되는 공간이라는 뜻이라고 봅니다. C object를 C 언어문법으로 표현하자면 & 연산자 (addressof: 주소추출연산자)를 쓸 수 있으면 모두 object인데 주소라는 개념을 설명하거나 기억부류같은 것을 설명할려면 storage 혹은 memory라는 용어를 써야 설명이 가능할테니까요. 그것 말고도 malloc - free를 통한 동적 memory 할당을 설명할려면 또 어떻게 설명해야하겠어요... ^_^.
말씀하신 문장은 다르게 표현해서 "상수는 C 표준에서 주소추출을 할 수 없는 것으로 정의한다"라고 이해하는 것이 좋을 것 같습니다.

lacovnk의 이미지

1) 좌변값, 우변값은 하드웨어 레벨로 내려가지 말고, 문법의 의미를 이해하는 것이 먼저 필요합니다.
좌변값, 우변값은 언어에서의 특징이지, 어떻게 하드웨어에서의 표현에 따라 결정되거나, 하드웨어의 표현을 지시하는 것은 아닙니다. (결과적으로 그렇게 보일지라도)

2) 포인터에 대해서는, 본지 오래되어서 가물가물하지만 [다시 체계적으로 배우는 C언어 포인터] 가 괜찮았습니다.
http://book.daum.net/detail/book.do?bookid=KOR9788956741147

kaeri17의 이미지

실제로 C에서는 어떤 값이 좌변값이 될 수 있냐 없냐에 대하여 저장 장소의 특성이 어느 정도 반영이 된다고 할 수 있습니다. 하지만, 나중에 C++까지 올라가면 결국 좌변값이 되냐 안되냐를 결정하는 것은 언어적인 특성이지, 하드웨어적인 저장장소가 아닙니다.

그리고 배열의 이름을 수정 못하는 것도 배열의 이름이 우변값이기 때문이라고 말하는 것은 실제적으로 옳을 지 몰라도 어폐가 있는 표현입니다. int a[3]; 에서 a 값이 C언어에서 편의상 첫 원소의 주소값으로 정의가 되어 있기 때문인게 먼저이고 그렇기 때문에 좌변값이 되지 못하는 것 입니다.

또한 대부분의 경우 메모리에 저장하는 존재도 우변값이 될 수 있습니다. 그냥 int a=3; 해 놓고 int b =a; 라고 하면 메모리 값이 우변값으로 쓰이게 되죠. 물론 좌변값이 될 수도 있죠. 똑같히 레지스터에 존재하는 변수도 좌변값이 될 수 있습니다. 레지스터의 주소값을 취득할 수 없는 것은 맞지만, C컴파일러가 알맞는 기계어로 변환 해 줍니다. 예를들어 기본적으로 함수 호출의 인자는 인자가 적을 경우 바로 레지스터에 저장 됩니다. 하지만 이 인자의 포인터를 얻는 연산을 하게 되면 경우에 따라 인자를 레지스터가 아닌 메모리에 저장하던지 아니면 * 연산자로 접근하는 C 문장을 직접 레지스터를 수정하도는 기계어로 컴파일 하던지 합니다.

klara의 이미지

첫 번째 줄의 a가 어떤 문장에서 대입연산자의 오른쪽에 등장했을 때와 동등한 상황으로로 봐도 되는 거죠(p = a)? 한 마디로 a는 값이기 때문에 또 값은 레지스터에 존재하기 때문에 즉 대상체(object)가 아니기 때문에, 대입연산을 할 수가 없는 게 맞는 겁니까? 여기까지가 제가 오랜 시간 포인터와 배열을 공부하면서 내린 결론입니다.

아니오. 상수라서 레지스터에 들어가고 혹은 레지스터에 들어있으므로 상수이고 하는게 아닙니다.
요즘 책에는 잘 소개되지 않는 내용이긴 하지만, C에는 레지스터 변수를 명시적으로 선언할수 있는 register라는 한정어도 존재합니다.
이런식으로요.

register int i;
for (i=0; i<MAX; ++i)
...

레지스터로 선언된 변수가 실제로 레지스터에 들어가냐 안들어가냐는 컴파일러마음이기는 하지만, 적어도 레지스터라는 공간과 좌변값/우변값은 상관없습니다.

저도 언어적인 면에서 '상수니까 대입이 안된다'라고만 하는게 최선으로 보입니다.
상수를 선언하기위한 const라는 한정자를 생각하면, 더이상 대입에 있어서 좌변값/우변값의 구분은 의미가 없어집니다.

loopbit@naver.com의 이미지

모두 감사합니다.

익명 사용자의 이미지

서로 계층(하드웨어와 C언어)이 다른 용어가 섞여서 사용되고 있는 것 같군요.
그점만 빼면 포인터와 배열 이름에 대한 이해는 대체로 정확하십니다.

배열이름이 좌변에 못오는 것은 그게 포인터 주소값으로 변환되어
더 이상 modifiable lvalue가 아니가 때문이죠.

배열이름이 단순히 lvalue가 아니다 라거나 포인터 상수다 라고 이해한다면
&, sizeof 연산자의 피연산자로 배열이름이 올 수 있는 이유를 설명하지 못합니다.

상수가 메모리 위에 없어서 라고 생각하기 보다는
문법적으로 볼때 대입 연산자의 좌변에 올 수 있는 피연산자 종류가 한정되어 있다 라고 생각하는 쪽이
더 C언어다운 사고방식입니다.

좌변값 우변값은 C 언어 레벨에서의 용어이고
레지스터는 하드웨어 위에서의 실제 구현에 대한 용어입니다.

우변값을 레지스터에서 처리하는게 속도 면에서 바람직하긴 하지만
우변값이 늘어나면 모두 다 레지스터 위에서 돌아갈 수 있는것도 아니고
메모리에서 처리될 수도 있지요.

비슷한 예로 C언어에서 register 키워드를 사용한다고 해서
그 변수들이 모두 레지스터 위에서 돌아가는 것은 아닙니다.
C언어 레벨에서의 정의는
이걸 붙여서 선언한 변수는 빈번하게 사용할 거니까 최대한 빨리 처리될 수 있도록 배려해라...
뭐 그정도였던걸로 기억합니다.

흔히 범하기 쉬운 오류가 서로 다른 계층의 지식들을 하나로 묶어서,
특히 특정 하드웨어에 기반해서 생각한다는 겁니다.
'특정 하드웨어에서는 내가 디버거 돌려보니까 이렇게 작동해, 그러니까 이게 진리야'
이렇게 직접 체험에 의존해서 어떤 한 경우만 절대 진리라고 생각하고,
나머지는 모두 잘못된 근거없는 지식이라 단정해 버리는 거죠.

추상적인 구조는 추상적인 구조 그 자체로 받아들이시고
그 추상적인 구조가 실제로 특정 하드웨어 위에서 구현될 때의 자잘한 특성에 대해서는
그 역시 추상적인 구조와는 별개의 것으로 취급해서 접근하는게 바람직합니다.

그리고 용어를 사용하실 때는 이게 어느 계층에서 어떤 맥락으로 사용되는가 그런걸 잘 구분해서
사용하는 것이 혼선을 막는 지름길입니다.

익명 사용자의 이미지

다시한번 강조하지만
절대 프로그래밍 언어를 하드웨어 레벨에서 이해하지 마시고
그냥 그대로 하드웨어와는 별개의 계층에서의
독립된 추상적인 구조로 이해하십시오.

물론 그 추상적인 구조가 실제로 하드웨어 레벨에서 어떻게 구현되는가는
그 나름대로 알아둘 필요가 있고 굉장히 중요한 지식이기도 합니다만
두개의 구분이 흐릿한 상태로 섞여서 받아들이는 것은
대단히 위험한 일입니다.

loopbit@naver.com의 이미지

예 익명님 말씀이 맞는 것 같습니다. 감사합니다.

댓글 달기

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