포인터변수의 크기가 4byte(OS에 따라 8byte)로 고정되어 있는 이유가 뭘까요?

souiss의 이미지

일반 변수와는 달리 포인터 변수는 타입에 관계없이 항상 4바이트를 유지하는데

크기가 100Kb가 넘는 구조체, 클래스를 가리키는 포인터라 할지라도 포인터 자체 크기는 항상 4바이트 입니다

이유가 뭘까요??

mydream의 이미지

2의 64제곱의 메모리로 알고 있는데요

souiss의 이미지

이미 적은 내용을 가지고 날카로운 댓글다는 이유가 뭔지...?

DarkSide의 이미지

위 분의 말씀은 64비트 시스템의 최대 메모리가 2의 64제곱이라는 말씀이고, 별로 틀리는 말은 아닌데요.
2의 64제곱이 8바이트라기 보다는 이러한 수를 표현하기 위해 8바이트가 필요하다고 해야 되겠죠.
초심자로 보이는데 조금 겸허한 자세가 필요해 보입니다.

souiss의 이미지

위 분의 말씀은 64비트 시스템의 최대 메모리가 2의 64제곱이라는 말씀이고, 별로 틀리는 말은 아닌데요.
저도 이 부분 알고있습니다 댓글 분께서 언급하신 개념이 틀렸다는 것이 아니구요
제가 질문에도 32비트운영체제냐 64비트 운영체제냐에 따라 4 또는 8바이트로 달라진다고 명시를 해놓았습니다
그 4바이트와 8바이트의 표현 범위를 물은게 아닙니다 굳이 제가 언급해놓은 내용을 답글로 같은 말을 날카롭게 다셨길래 저도 좀 날카롭게 댓글이 나갔네요..
밑에 제 답글보시면 보이다시피 초심자이기 때문에 말씀해주시는 부분들 지적해주시는 부분들 겸허히 받아들이고 다시 공부하고 있습니다만
초심자에게 말을 둥글게 해주셨으면 좋겠네요 ^^

익명 사용자의 이미지

애초에 말씀하시는 정수값 이라는게 무슨 의미인지부터 정의해야 합니다.

정수(int) 타입만을 기준으로 한다면 이건 컴파일러에 따라 달라집니다.
64비트 타겟일 때 프로그래밍 모델은 총 4가지가 있습니다.
LP64 , LLP64, ILP64, SILP64

https://ko.wikipedia.org/wiki/64%EB%B9%84%ED%8A%B8#64.EB.B9.84.ED.8A.B8_.EB.8D.B0.EC.9D.B4.ED.84.B0_.EB.AA.A8.EB.8D.B8

이는 위의 표를 참고하시면 됩니다. 예로 gcc 와 vs 는 서로 다른 모델을 사용합니다.

포인터 변수가 고정되는 이유는 당연히 가질 수 있는 최대 어드레스값 만큼은 무조건 차지해야 하기 때문입니다.
32비트 시스템이면 기본적으로 주소 공간에서 최대 0xffffffff 까지 액세스할 일이 있을 수 있는데(이론적으로)
당연히 간접 액세스시에 4바이트를 필요로 하고, 실제 인스트럭션의 opcode 도 그렇게 구성되어 있습니다.

포인터의 타입은 C 에서 정의한 추상적인 개념이고, 어셈블리 레벨에선 아무 의미 없습니다. 주소만 있을 뿐.

souiss의 이미지

감사합니다 !! 많이 알아가네요
너무 궁금했는데 드디어 알았네요

klenui의 이미지

언급하신 내용이 맞구요..
옛날 컴 구조 책 보면, word 라는 단어가 나옵니다.
https://en.wikipedia.org/wiki/Word_(computer_architecture)

요즘은 별로 쓰지 않는 말인게 거의 intel architecture아니면 arm이니까 따로 word를 말할 필요가 없습니다.
그냥 32bit 머신에서 포인터는 4바이트라고 외우면 되니까요.
옛날 여러 CPU 구조들이 백가쟁명할 때 이야기입니다.

결국, 컴퓨터의 구조상 가장 다루기 쉬운 형태의 값이 word인데, 달리말해 assembler의 register가 word 단위로 되어 있고
포인터라고 해봐야 결국 register를 이용한 load/store 과정이니까 당연히 포인터의 크기는 word의 크기가 됩니다.
호환성과 성능을 위해서 예외가 있긴 하겠습니다만..

초기 C언어에서는 word가 8비트냐 16비트냐 이럴때였기 때문에(초기 임베디드 CPU 중, 엄한 환경에서도 동작해야 되는 경우는 4bit도 있었던 걸로 기억합니다.)
char 8bit, int 16bit, long 32bit 이렇게 나눴는데, 정확한 계기는 모르겠지만, 32bit 넘어가면서 char 8bit, int 32bit, long 32bit, long long 64bit 이렇게 바뀐것 같습니다. 잘은 기억안나는데, C언어 스펙에 int는 word보다 작거나 같고, long은 word와 같거나 보다 크다..뭐 이런식으로 정의되었던 것 같네요.

라스코니의 이미지

제 생각에는 주솟값==정수값 인데,
정수값을 신속하게 처리하기 위해서는 cpu가 가장 빠르게 처리하는 자료형인 int형을
사용하기 때문에 무조건 4바이트. 라고 생각합니다(OS에 따라선 8byte가 되겠죠)

C언어(또는 모든 언어?)에서 주소(pointer)는 일반 값의 체계와는 전혀 다르다고 보셔야 됩니다.
포인터(주소)는 정수(양의 정수)로 표현할 수는 있지만 C 언어에서는 그 값의 조작이 제한되어 있습니다. 그래서 주소값 == 정수값이라고 보시면 안됩니다.
따라서 주소값을 정수 형태로 casting 해서 쓰는 것도 조심해야 합니다.

주소값은 가상메모리가 되었던, 물리 메모리가 되었던 메모리를 액세스할 수 있는 번지값입니다.
32 bit OS 나 64 bit OS는 사용할 수 있는 메모리가 차이가 있기 때문에 포인터 값의 범위도 덩달아서 차이가 나는 것입니다.

souiss의 이미지

주솟값==정수값 지적해주셔서 다시 공부했습니다 답글 많은 도움 되었습니다 ^^

souiss의 이미지

그런데 C 언어에서는 그 값의 조작이 제한되어 있습니다 이게 무슨 뜻인가요?

라스코니의 이미지

C언어에서 포인터는 조작이
ptr++
ptr--

정도만 가능합니다.

그 외에는 캐스팅을 해서 해야 합니다. 예를 들어
ptr + (unsigned int *)0x2000 등으로요.

캐스팅시 생각했던 것 외로 동작할 수 있기 때문에 주의가 필요합니다.

souiss의 이미지

답 감사합니다

익명 사용자의 이미지

좀 더 정확히 말하자면 포인터에 대한 산술 연산은

(포인터) + (정수형) = (포인터)
(포인터) - (정수형) = (포인터)
(포인터) - (포인터) = (정수형) /* 단, 같은 타입의 포인터끼리만 가능 */

만 가능합니다.

ptr + (unsigned int *)0x2000는 유효하지 않은 수식입니다. 오타라고 생각되지만...

souiss의 이미지

자세한답변 감사드립니다.^^

라스코니의 이미지

아닙니다. 임베디드에서 많이 사용하며 컴파일도 잘 되는 겁니다 ~~

unsigned int *VIDEO_RAM_BASE = (unsigned int *)0x80000000;

*(unsigned int *)(VIDEO_RAM_BASE + 0x2000) = 0x1;

등등...

임베디드에서는 필수 코드죠 ~

익명 사용자의 이미지

님이 위에 적은 코드와 전혀 다른 코드를 들고 와서 잘된다고 우기면 안되죠.

ptr + (unsigned int *)0x2000 -> (포인터) + (포인터)에 해당.

gcc의 경고 - warning: assignment makes integer from pointer without a cast

*(unsigned int *)(VIDEO_RAM_BASE + 0x2000) -> (포인터) + (정수형)에 해당함

익명 사용자의 이미지

다시 보니까 위에 에러메시지는 테스트용 예제를 잘못 작성한 결과고
gcc는 (포인터)+(포인터)에 대해 아무 에러나 경고 메시지를 출력하지는 않네요.

그렇다 하더라도 (포인터)+(포인터)가 올바른 코드는 아닙니다.
C 표준은 덧셈 연산의 두 피연산자에 대해 둘 다 산술형이거나 하나는 포인터 다른하나는 정수형이기를 요구하기 때문입니다.

6.5.6 Additive operators
2. For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)

jeff_an의 이미지

CPU 내의 메모리 버스와도 관련있다고 들은것 같네요.

익명 사용자의 이미지

포인터 타입의 크기는 CPU의 ISA에서 메모리의 주소를 어떤 크기로 받아들이는지에 따른 것입니다.

잠깐 16비트 도스 시절 얘기를 해 볼까요?

인텔 8086 체계에서는 포인터에 near pointer와 far pointer의 두 타입이 존재했었습니다.

그것은 real mode이고, segmentation이라는 특수한 환경적 제약 때문에 존재했던 것으로,

near pointer는 16비트(Offset 만으로 구성), far pointer는 32비트의 값(Segment:Offset 으로 구성)을 가집니다.

포인터의 크기는 메모리 주소의 표현 범위에 따라 결정되고, 메모리 주소의 범위는 MAR(Memory Address Register) 레지스터의 크기에 의해

결정되기 때문에 워드 사이즈의 영향을 받지, int 형의 크기와는 아무런 상관이 없습니다.

int 형은 역사적으로 B언어에서는 word 타입이기 때문에 32비트 시절까지는 일반적으로 CPU의 워드 크기를 따라갔지만,

이후 하위 호환성 등을 이유로 운영체제마다(심할 경우 같은 운영체제라도 컴파일러마다) int 형의 크기가 제각각 다를 수 있습니다.

운영체제의 시스템 콜과의 호환성 때문에 자료형의 크기는 대개 운영체제의 시스템 콜 디자인에 따라가기 때문이지요.

===

http://cafe.daum.net/codeinside

souiss의 이미지

더 깊이 알게되는것 같아 좋네요 답글 감사합니다

댓글 달기

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