포인터가 C 언어로 보유하는 데이터의 "유형"은 무엇입니까?


30

포인터에 주소가 있다는 것을 알고 있습니다. 포인터의 타입은 그들이 가리키는 데이터의 "타입"에 기초하여 "일반적으로"알려져 있다는 것을 알고 있습니다. 그러나 포인터는 여전히 변수이며 보유한 주소에는 데이터 "유형"이 있어야합니다. 내 정보에 따르면 주소는 16 진수 형식입니다. 그러나 나는 여전히이 16 진수 데이터의 "유형"이 무엇인지 모른다. (나는 16 진수가 무엇인지 알고 있지만 10CBA20예를 들어이 문자열입니까? 정수? 무엇입니까? 주소에 액세스하고 조작하려고 할 때 .. 자체를 유형을 알아야합니다. 내가 묻는 이유입니다.)


17
포인터는 변수 가 아니라 입니다. 변수는 값을 보유합니다 (그리고 유형이 포인터 유형 인 경우 해당 값은 포인터이며 의미가있는 메모리 영역의 주소 일 수 있습니다). 주어진 메모리 영역은 다양한 유형의 다양한 값을 보유하는 데 사용될 수 있습니다.
Basile Starynkevitch

29
"주소는 16 진수 형식입니다."아니요, 디버거 또는 라이브러리 형식 비트 일뿐입니다. 같은 주장으로 바이너리 또는 8 진수라고 말할 수 있습니다.
usr

당신은에 대해 물어 더 나을 것 형식 이 아닌 유형 . 따라서 아래의 오프 피스트 답변은 ... (킬리안이 발견되었지만).
Monica

1
여기서 더 깊은 문제는 OP의 유형에 대한 이해라고 생각합니다 . 그것이 내려지면 프로그램에서 조작하는 값은 메모리의 비트입니다. 형식은 프로그래머가 어셈블리 코드를 생성 할 때 해당 비트를 처리하는 방법을 컴파일러에 알려주는 방법입니다.
Justin Lardinois 2016 년

모든 답변으로 편집하기에는 너무 늦었다 고 가정하지만이 질문은 하드웨어 및 / 또는 운영 체제를 제한 한 경우 (예 : "x64 Linux") 더 좋을 것입니다.
hyde

답변:


64

포인터 변수의 유형은 .. pointer입니다.

C에서 공식적으로 허용되는 작업은 다른 포인터 또는 특수 NULL / 0 값과 비교하여 정수를 더하거나 빼거나 다른 포인터로 캐스팅하는 것입니다.

정의되지 않은 동작을 수락하면 실제 값이 무엇인지 확인할 수 있습니다. 일반적으로 정수와 같은 종류의 기계어이며 일반적으로 정수 유형과 무손실로 캐스트 될 수 있습니다. (많은 Windows 코드가 DWORD 또는 HANDLE typedefs에 포인터를 숨겨서이 작업을 수행합니다).

메모리가 평평하지 않기 때문에 포인터가 단순하지 않은 아키텍처가 있습니다. DOS / 8086 '가까운'및 '먼'; PIC의 다른 메모리 및 코드 공간.


2
당신은 또한 두 포인터의 차이를 취할 수 있습니다 p1-p2. 결과는 부호있는 정수 값입니다. 특히&(array[i])-&(array[j]) == i-j
MSalters

13
실제로, 정수형으로의 변환도 명시되어 intptr_t있으며 , 특히 uintptr_t포인터 값에 대해 "충분히 큰"것으로 보장됩니다.
Matthieu M.

3
변환 작업에 의존 할 수 있지만 정수와 포인터 간의 매핑은 구현 정의되어 있습니다. (단 하나의 예외는 0-> null이며, 0이 상수 IIRC 인 경우에만 지정됩니다.)
cHao

7
pprintf에 지정자를 추가 하면 c에서 구현에 따라 동작하는 경우 void 포인터의 사람이 읽을 수있는 표현을 정의 할 수 있습니다.
dmckee

6
이 답변은 일반적으로 올바른 생각을 가지고 있지만 특정 주장에 실패합니다. 정수형에 대한 포인터를 강제하는 것은 정의되지 않은 동작이 아니며 Windows HANDLE 데이터 형식은 포인터 값이 아닙니다 (이것은 정수 데이터 형식에 숨겨진 포인터가 아니며 산술을 방지하기 위해 포인터 형식에 숨겨진 정수입니다).
Ben Voigt 2016 년

44

너무 복잡해

주소는 정수, 마침표입니다. 이상적으로는 참조 된 메모리 셀의 수입니다 (실제로는 세그먼트, 가상 메모리 등으로 인해 더 복잡해집니다).

16 진 구문은 프로그래머의 편의를 위해서만 존재하는 완전한 소설입니다. 0x1A와 26은 정확히 같은 유형의 숫자와 정확히 같은 숫자이며 컴퓨터가 사용하는 것도 아니고 내부적으로 컴퓨터는 항상 00011010 (일련의 이진 신호)을 사용합니다.

컴파일러가 포인터를 숫자 로 취급 할 수 있는지 여부 는 언어 정의에 따라 결정됩니다. "시스템 프로그래밍"언어는 전통적으로 후드에서 작동 방식에 대해 더 투명하지만 "고수준"언어는 베어 메탈을 숨기려고하는 경우가 더 많습니다 프로그래머로부터-포인터가 숫자라는 사실과 일반적으로 가장 일반적인 유형의 숫자 ​​(프로세서 아키텍처만큼 많은 비트가있는 숫자)에 대해서는 아무런 변화가 없습니다.


26
주소는 정수가 아닌 것이 가장 확실 합니다. 부동 소수점 숫자는 가장 확실히 하듯 하지 단지 정수.
gnasher729 2016 년

8
과연. 가장 잘 알려진 반례는 포인터가 두 개의 정수인 Intel 8086 입니다.
MSalters 2016 년

5
@Rob 세그먼트 화 된 메모리 모델에서 포인터는 세그먼트가 암시 된 단일 값 (세그먼트의 시작에 대한 주소, 오프셋)이거나 세그먼트 / 선택기 및 오프셋 쌍일 수 있습니다. (인텔은 "셀렉터"라는 용어를 사용했다고 생각합니다. 검색하기에는 너무 게으른 것 같습니다.) 8086에서 이들은 두 개의 16 비트 정수로 표시되어 하나의 20 비트 물리적 주소를 형성했습니다. (예, 만약 당신이 그렇게 기울어 졌다면, 많은 다른 방법으로 같은 메모리 셀을 다룰 수 있습니다 : address = (segment << 4 + offset) & 0xfffff.) 이것은 실제 모드에서 실행될 때 모든 x86 호환을 통해 진행되었습니다.
CVN

4
장기 어셈블러 프로그래머로서 컴퓨터의 메모리는 정수를 보유한 메모리 위치에 불과하다는 것을 증명할 수 있습니다. 그러나 그것들을 어떻게 처리하고 그 정수가 나타내는 것이 무엇인지 추적하는 것이 중요합니다. 예를 들어, 내 시스템에서 10 진수 4075876853은 x'F2F0F1F5 '로 저장되는데, 이는 EBCDIC의 문자열'2015 '입니다. Decimal 2015는 000007DF로 저장되는 반면 x'0002015C '는 10 진수 2015를 팩형 10 진수 형식으로 나타냅니다. 어셈블러 프로그래머는이를 추적해야합니다. 컴파일러는 HL 언어를 위해이를 수행합니다.
Steve Ives

7
주소는 정수와 일대일로 대응 될 수 있지만 컴퓨터의 다른 모든
것들도 가능

15

포인터는 바로 그 포인터입니다. 다른 것이 아닙니다. 그것이 다른 것이라고 생각하려고하지 마십시오.

C, C ++ 및 Objective-C와 같은 언어에서 데이터 포인터는 네 가지 가능한 값을 갖습니다.

  1. 포인터는 객체의 주소 일 수 있습니다.
  2. 포인터는 배열의 마지막 요소를 지나칠 수 있습니다.
  3. 포인터는 널 포인터 일 수 있으며, 이는 아무 것도 가리 키지 않음을 의미합니다.
  4. 포인터는 불확실한 값을 가질 수 있습니다. 즉, 쓰레기이며, 사용하려고하면 모든 것이 발생할 수 있습니다 (나쁜 일 포함).

함수를 식별하거나 널 함수 포인터이거나 불확실한 값을 갖는 함수 포인터도 있습니다.

다른 포인터는 C ++에서 "멤버를 가리키는 포인터"입니다. 이들은 메모리 주소가 아닌 것이 가장 확실 합니다! 대신 클래스 의 모든 인스턴스 멤버를 식별합니다 . Objective-C에는 "특정 메소드 이름 및 인수 이름을 가진 인스턴스 메소드에 대한 포인터"와 같은 선택기가 있습니다. 멤버 포인터와 마찬가지로 모든 클래스의 모든 메소드가 동일하게 보이는 한 모든 메소드를 식별 합니다 .

특정 컴파일러가 포인터를 구현하는 방법을 조사 할 수 있지만 이는 완전히 다른 질문입니다.


4
함수에 대한 포인터와 C ++에는 멤버에 대한 포인터가 있습니다.
sdenham

멤버에 대한 C ++ 포인터는 메모리 주소가 아닙니까? 물론입니다. class A { public: int num; int x; }; int A::*pmi = &A::num; A a; int n = a.*pmi;변수 pmi에 메모리 주소, 즉 코드의 마지막 줄이 설정 한대로 class num인스턴스 a의 구성원 주소가 포함되어 있지 않으면 변수 가 많이 사용되지 않습니다 A. 이것을 일반 int포인터로 캐스팅 하고 (컴파일러가 경고를 줄 수도 있지만) 성공적으로 참조 해제 할 수 있습니다 (다른 포인터의 구문 설탕임을 증명).
dodgethesteamroller

9

포인터는 RAM의 저장 단어를 주소 지정 (읽기 또는 쓰기 목적으로 고유하게 식별)하는 비트 패턴입니다. 과거와 기존의 이유로 업데이트 단위는 8 비트로 영어에서는 "바이트"로, 프랑스어에서는 좀 더 논리적으로 옥텟으로 알려져 있습니다. 이것은 어디에나 있지만 본질적인 것은 아니다. 다른 크기가 존재합니다.

내가 정확하게 기억한다면 29 비트 단어를 사용하는 컴퓨터가 한 대있었습니다. 이것이 2의 거듭 제곱 일뿐만 아니라, 심지어 최고입니다. 나는 이것이 SILLIAC이라고 생각했지만 관련 Wikipedia 기사는 이것을 지원하지 않습니다. CAN BUS는 29 비트 주소를 사용하지만 관례 적으로 네트워크 주소는 기능적으로 동일한 경우에도 포인터로 언급되지 않습니다.

사람들은 포인터가 정수라고 주장합니다. 이것은 본질적인 것도 아니고 필수적인 것도 아니지만 , 비트 패턴을 정수로 해석 하면 유용한 순서 품질이 나오고, "문자열"및 "배열"과 같은 구문을 매우 직접적으로 (따라서 작은 하드웨어에서 효율적으로) 구현할 수 있습니다. 연속 기억의 개념은 서수 인접성에 따라 달라지며 상대 위치 지정이 가능합니다. 정수 비교 및 ​​산술 연산을 의미있게 적용 할 수 있습니다. 이러한 이유로 스토리지 주소 지정을위한 워드 크기와 ALU (정수 연산을 수행하는 것) 간에는 항상 강한 상관 관계가 있습니다.

때로는 두 사람이 일치하지 않습니다. 초기 PC에서는 주소 버스의 폭이 24 비트였습니다.


요즘 일반적인 OS에서 Nitpick은 포인터가 가상 메모리의 위치를 ​​식별하며 실제 RAM 단어와 직접 관련이 없습니다 (가상 메모리 위치는 OS에서 0으로 알려진 메모리 페이지에있는 경우 물리적으로 존재하지 않을 수도 있음) ).
hyde

@hyde-당신의 주장은 분명히 의도 한 맥락에서 장점이 있지만, 지배적 인 컴퓨터 형태는 임베디드 컨트롤러이며, 가상 메모리와 같은 놀라운 것은 최근 배포가 제한적인 혁신입니다. 또한 당신이 지적한 것은 OP가 포인터를 이해하는 데 도움이되지 않습니다. 나는 역사적 맥락에 따라 조금 덜 자의적이라고 생각했다.
Peter Wone

RAM에 대해 이야기하면 OP가 이해하는 데 도움이되는지 모르겠습니다. 질문은 포인터가 실제로 무엇인지에 대한 입니다. 아, 정의에 의한 c 포인터의 또 다른 nitpick 은 (CPU 워드 크기가 바이트 크기와 동일하지 않는 한) 워드가 아닌 바이트를 가리 킵니다 ( char*예 : 메모리 복사 / 비교를 위해 sizeof char==1C 표준에 의해 정의 된대로 안전하게 캐스팅 될 수 있음 ).
hyde

기본적으로 포인터는 저장을위한 해시 키입니다. 언어와 플랫폼이 변하지 않습니다.
Peter Wone

문제는 c 에 관한 것입니다 포인터 입니다. 해시 테이블이없고 해시 알고리즘이 없기 때문에 포인터는 확실히 해시 키가 아닙니다. 그것들은 당연히 일종의지도 / 사전 키 ( "지도"의 충분히 넓은 정의를위한)이지만 해시 키는 아닙니다 .
hyde

6

기본적으로 모든 최신 컴퓨터는 비트 푸시 머신입니다. 일반적으로 바이트, 워드, 드 워드 또는 q 워드라고하는 데이터 클러스터에서 비트를 푸시합니다.

바이트는 8 비트, 워드 2 바이트 (또는 16 비트), 드 워드 2 워드 (또는 32 비트) 및 q 워드 2 드 워드 (또는 64 비트)로 구성됩니다. 비트를 정렬하는 유일한 방법은 아닙니다. 종종 SIMD 명령에서 128 비트 및 256 비트 조작도 발생합니다.

조립 지침은 레지스터에서 작동하며 메모리 주소는 일반적으로 위 형식 중 하나로 작동합니다.

ALU (산술 논리 단위)는 정수 (일반적으로 2의 보수 형식)를 나타내는 것처럼 비트 번들과 부동 소수점 값 (일반적으로 IEEE 754 스타일 floatdouble) 인 것처럼 FPU에서 작동 합니다. 다른 부분은 일부 형식, 문자, 테이블 항목, CPU 명령어 또는 주소의 번들 데이터 인 것처럼 작동합니다.

일반적인 64 비트 컴퓨터에서 8 바이트 (64 비트) 번들은 주소입니다. 이러한 주소는 일반적으로 16 진수 형식 (예 :)으로 표시 0xabcd1234cdef5678되지만 이는 사람이 비트 패턴을 쉽게 읽을 수있는 방법입니다. 각 바이트 (8 비트)는 2 개의 16 진 문자로 작성됩니다 (각각의 16 진 문자 (0 ~ F)는 4 비트를 나타냄).

실제로 진행되고있는 것은 (일부 레벨의 경우) 일반적으로 레지스터에 저장되거나 메모리 뱅크의 인접한 위치에 저장되는 비트가 있으며 다른 인간에게 설명하려고합니다.

포인터를 따라 가면 메모리 컨트롤러에 해당 위치에 데이터를 제공하도록 요청하는 것으로 구성됩니다. 일반적으로 메모리 컨트롤러에 특정 위치 (일반적으로 연속적인 위치의 암시 적 범위)에서 특정 수의 바이트를 요청하면, 들어 가지 않을 다양한 메커니즘을 통해 전달됩니다.

이 코드는 일반적으로 데이터를 가져올 대상 (레지스터, 다른 메모리 주소 등)을 지정하며 일반적으로 정수를 기대하는 레지스터에 부동 소수점 데이터를로드하거나 그 반대의 경우도 좋지 않습니다.

C / C ++의 데이터 유형은 컴파일러가 추적하는 내용이며 생성되는 코드를 변경합니다. 일반적으로 데이터에 실제로 어떤 유형이든 만드는 본질적인 것은 없습니다 . 코드에 의해 정수와 같은 방식으로 (또는 플로트와 같은 방식으로 또는 주소와 같은 방식으로) 조작되는 비트 모음 (바이트로 정렬 됨).

이에 대한 예외가 있습니다. 특정 것들이 다른 종류 의 비트 인 아키텍처가 있습니다 . 가장 일반적인 예는 보호 된 실행 페이지입니다. CPU에 지시하는 명령은 비트이지만 런타임에는 실행할 코드가 포함 된 (메모리) 페이지가 특별히 표시되고 수정할 수 없으며 표시되지 않은 페이지는 실행할 수 없습니다 실행 페이지로.

읽기 전용 데이터 (물리적으로 기록 할 수없는 ROM에 저장된 경우도 있음), 정렬 문제 (일부 프로세서는 double특정 방식으로 정렬되지 않은 경우 메모리에서 s를 로드 할 수 없음 또는 특정 정렬이 필요한 SIMD 명령) 및 다른 아키텍처 문제.

위의 세부 수준조차 거짓말입니다. 컴퓨터는 비트를 "진정하게"밀지 않고 전압과 전류를 밀고 있습니다. 이러한 전압과 전류는 때때로 추상화 비트 수준에서 "추정 된"기능을 수행하지 않습니다. 칩은 대부분의 이러한 오류를 감지하고 더 높은 수준의 추상화를 알 필요없이 수정하도록 설계되었습니다.

그것조차 거짓말입니다.

각 추상화 레벨은 아래의 것을 숨기고 인쇄하기 위해 Feynman 다이어그램을 염두에 두지 않고 문제 해결에 대해 생각할 수 있습니다. "Hello World" .

따라서 충분한 수준의 정직에서 컴퓨터는 비트를 푸시하며 이러한 비트는 사용 방식에 따라 의미가 부여됩니다.


3

사람들은 포인터가 정수인지 아닌지에 대해 많은 것을 만들었습니다. 실제로 이러한 질문에 대한 답변이 있습니다. 그러나, 당신은 희미한 마음이 아닌 사양의 땅으로 한 걸음 나아가 야 할 것입니다. 우리는 C 사양을 살펴볼 것입니다. ISO / IEC 9899 : TC2를 .

6.3.2.3 포인터

  1. 정수는 임의의 포인터 유형으로 변환 될 수 있습니다. 이전에 지정된 경우를 제외하고 결과는 구현에 따라 정의되고 올바르게 정렬되지 않았으며 참조 된 유형의 엔티티를 가리 키지 않을 수 있으며 트랩 표현 일 수 있습니다.

  2. 모든 포인터 유형은 정수 유형으로 변환 될 수 있습니다. 이전에 지정된 경우를 제외하고 결과는 구현 정의됩니다. 결과를 정수 유형으로 표시 할 수 없으면 동작이 정의되지 않은 것입니다. 결과는 정수 유형의 값 범위에있을 필요는 없습니다.

이제이를 위해 몇 가지 일반적인 사양 용어를 알아야합니다. "구현 정의"는 모든 단일 컴파일러가 다르게 정의 할 수 있음을 의미합니다. 실제로 컴파일러는 컴파일러 설정에 따라 다른 방식으로 정의 할 수도 있습니다. 정의되지 않은 동작은 컴파일러가 컴파일 시간 오류 제공에서 설명 할 수없는 동작에 이르기까지 완벽하게 작동하는 것에 이르기까지 모든 작업을 수행 할 수 있음을 의미합니다.

이것으로부터 우리는 기본 스토리지 형식이 지정되지 않았 음을 알 수 있습니다. , 정수 유형으로 변환 수 있습니다. 이제 진실은, 실제로 태양 아래있는 모든 컴파일러는 정수 주소로 후드 아래의 포인터를 나타냅니다 (단지 1이 아닌 2 개의 정수로 표현 될 수있는 소수의 특별한 경우가 있지만). 10 자 문자열로 주소 지정!

C에서 빨리 감기하고 C ++ 사양을 살펴보면와 함께 조금 더 명확 해지지 reinterpret_cast만 이것은 다른 언어이므로 값이 다를 수 있습니다.

ISO / IEC N337 : C ++ 11 초안 사양 (초안 만 가지고 있음)

5.2.10 재 해석 캐스트

  1. 포인터는이를 보유하기에 충분히 큰 일체형으로 명시 적으로 변환 될 수 있습니다. 매핑 함수는 구현 정의되어 있습니다. [참고 : 기본 시스템의 주소 구조를 아는 사람들에게는 놀라지 않습니다. — 끝 주] std :: nullptr_t 유형의 값은 정수 유형으로 변환 될 수 있습니다. 변환은 (void *) 0을 정수 유형으로 변환하는 것과 동일한 의미와 유효성을 갖습니다. [참고 : reinterpret_cast를 사용하여 모든 유형의 값을 std :: nullptr_t 유형으로 변환 할 수 없습니다. — 끝 참고]

  2. 정수형 또는 열거 형의 값을 포인터로 명시 적으로 변환 할 수 있습니다. 충분한 크기의 정수로 변환 된 포인터 (구현물에 존재하는 경우)와 동일한 포인터 유형으로 돌아가는 포인터는 원래 값을 갖습니다. 포인터와 정수 사이의 매핑은 그렇지 않으면 구현 정의됩니다. [참고 : 3.7.4.3에 설명 된 경우를 제외하고 이러한 변환 결과는 안전하게 파생 된 포인터 값이 아닙니다. — 끝 노트]

여기에서 볼 수 있듯이 C ++은 몇 년이 더 길어 정수에 대한 매핑이 존재한다고 가정하는 것이 안전하다는 것을 알았으므로 더 이상 정의되지 않은 동작에 대한 이야기가 없습니다 (4 부분과 "구현에 해당되는 경우"라는 문구가있는 5)


이제 이것에서 무엇을 제거해야합니까?

  • 포인터의 정확한 표현은 구현 정의입니다. (실제로, 좀 더 지저분하게 만들기 위해 일부 소형 임베디드 컴퓨터는 사용하는 주소 앨리어싱 트릭을 지원하기 위해 주소 255로 널 포인터 (void ) 0을 나타냄) *
  • 메모리에서 포인터의 표현에 대해 질문해야한다면 프로그래밍 경력에서 포인터를 다루려는 지점에 있지 않을 것입니다.

가장 좋은 방법은 (char *)로 캐스팅하는 것입니다. C 및 C ++ 사양은 배열과 구조체의 패킹을 지정하는 규칙으로 가득 차 있으며, 항상 char *에 대한 포인터를 캐스팅 할 수 있습니다. char은 항상 1 바이트입니다 (C에서는 보장되지 않지만 C ++ 11에서는 언어의 필수 부분이되었으므로 어느 곳에서나 1 바이트라고 가정하는 것이 상대적으로 안전합니다). 이를 통해 구현의 특정 포인터 표현을 알 필요없이 바이트 단위로 포인터 산술을 수행 할 수 있습니다.


함수 포인터를 반드시로 캐스팅 할 수 있습니까 char *? 코드와 데이터를위한 별도의 주소 공간이있는 가상 머신을 생각하고 있습니다.
Philip Kendall 2016 년

@PhilipKendall 좋은 지적입니다. 사양의 해당 부분을 포함하지 않았지만 함수 포인터는 정확히 발생하는 문제 때문에 사양의 데이터 포인터와 완전히 다른 것으로 취급됩니다. 멤버 포인터도 다르게 취급됩니다 (그러나 그들은 매우 다르게 행동합니다)
Cort Ammon-Reinstate Monica

A char는 C에서 항상 1 바이트입니다. C 표준에서 인용하면 : "sizeof 연산자는 피연산자의 크기 (바이트)를 생성합니다"및 "char, unsigned char 또는 signed char 유형을 가진 피연산자에 sizeof가 적용될 때, 결과는 1입니다. " 아마도 당신은 바이트가 8 비트 길이라고 생각할 것입니다. 반드시 그런 것은 아닙니다. 표준을 준수하려면 바이트에 8 비트 이상이 포함되어야합니다.
David Hammen 2016 년

이 스펙 은 포인터와 정수 유형 사이의 변환 을 설명 합니다. 타입들 사이의 "변환"은 타입의 동등성을 의미하지 않으며, 메모리에서 두 타입의 이진 표현이 동일한 비트 패턴을 가질 것이라는 것을 항상 명심해야한다. (ASCII는 EBCDIC로 "변환 될 수 있습니다. 빅 엔디안은 리틀 엔디안으로"변환 될 수 있습니다. "
user2338816

1

대부분의 아키텍처에서 포인터 유형은 기계 코드로 변환 된 후에는 존재하지 않습니다 ( "뚱뚱한 포인터"제외). 그러므로에 대한 포인터 는 적어도 자체적으로에 대한 int포인터와 구별 할 수 없습니다 double. *

[*] 그래도 적용하는 작업의 종류에 따라 추측 할 수 있습니다.


1

C 및 C ++에 대해 이해해야 할 중요한 것은 실제로 유형이 무엇인지입니다. 그들이 실제로하는 일은 컴파일러에게 비트 / 바이트 세트를 해석하는 방법을 알려주는 것입니다. 다음 코드로 시작하자 :

int var = -1337;

아키텍처에 따라 정수에는 일반적으로 해당 값을 저장할 32 비트 공간이 제공됩니다. 즉, var가 저장된 메모리의 공간은 "11111111 11111111 11111010 11000111"또는 16 진수 "0xFFFFFAC7"과 비슷합니다. 그게 다야. 그것이 그 위치에 저장된 전부입니다. 모든 유형은 컴파일러에게 해당 정보를 해석하는 방법을 알려줍니다. 포인터도 다르지 않습니다. 내가 이런 식으로하면 :

int* var_ptr = &var;   //the ampersand is telling C "get the address where var's value is located"

그런 다음 컴파일러는 var의 위치를 ​​가져온 다음 첫 번째 코드 조각이 값 -1337을 저장하는 것과 같은 방식으로 해당 주소를 저장합니다. 저장 방법과 사용 방법에는 차이가 없습니다. var_ptr을 int에 대한 포인터로 만든 것은 중요하지 않습니다. 원한다면 할 수 있습니다.

unsigned int var2 = *(unsigned int*)var_ptr;

그러면 var (0xFFFFFAC7)의 16 진수 값이 var2의 값을 저장하는 위치에 복사됩니다. var2를 사용한다면 값은 4294965959가 될 것입니다. var2의 바이트는 var와 동일하지만 숫자 값이 다릅니다. 우리는 그 비트가 부호없는 long을 나타낸다고 말했기 때문에 컴파일러는 그것들을 다르게 해석했습니다. 포인터 값에 대해서도 동일한 작업을 수행 할 수 있습니다.

unsigned int var3 = (unsigned int)var_ptr;

이 예제에서 var의 주소를 나타내는 값을 부호없는 int로 해석하게됩니다.

잘하면 이것은 당신을 위해 일을 명확히하고 C가 어떻게 작동하는지에 대한 더 나은 통찰력을 제공합니다. 당신이 있습니다 해서는 안 나는 실제 생산 코드에서 아래 두 줄에서 한 미친 것들 중 하나를 수행합니다. 그것은 단지 시연을위한 것이었다.


1

정수.

컴퓨터의 주소 공간은 0부터 시작하여 순차적으로 번호가 매겨지고 1 씩 증가합니다. 따라서 포인터는 주소 공간의 주소에 해당하는 정수를 보유합니다.


1

유형이 결합됩니다.

특히 특정 유형은 마치 자리 표시 자와 함께 매개 변수화 된 것처럼 결합됩니다. 배열 및 포인터 유형은 다음과 같습니다. 그것들은 하나의 그러한 자리 표시자를 가지고 있는데, 이것은 배열의 요소 유형 또는 각각 지적되는 것입니다. 기능 유형도 이와 같습니다. 매개 변수에 대해 여러 개의 자리 표시 자와 반환 유형에 대한 자리 표시자를 가질 수 있습니다.

char에 대한 포인터를 보유하도록 선언 된 변수의 유형은 "pointer to char"입니다. int에 대한 포인터에 대한 포인터를 보유하도록 선언 된 변수는 "int에 대한 포인터에 대한 포인터"유형을 갖습니다.

역 참조 작업을 통해 "포인터를 가리키는 포인터"유형의 값을 "포인터를 int"로 변경할 수 있습니다. 따라서 유형의 개념은 단어뿐만 아니라 수학적으로 중요한 구성으로, 유형의 값으로 수행 할 수있는 작업 (예 : 역 참조 또는 매개 변수로 전달 또는 변수에 할당)을 결정합니다. 인덱싱, 산술 및 증분 / 감소 연산).

추신 : 당신이 유형에 깊이 들어가고 싶다면이 블로그를보십시오 : http://www.goodmath.org/blog/2015/05/13/expressions-and-arity-part-1/

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.