2011-07-27 1 views
14

그래서 우리는 내가 배열이 있다고 가정하자, 나는 'A'의 형식을 확인한다면 지금T 배열이 T 포인터로 쇠약 해지면 배열 T로 다시 변환 할 수 있습니까?

int a[3] = { 1, 2, 3 }; 

을 내 컴퓨터에서 나는 얻을 :

cout<<typeid(a).name(); // prints 'A3_i' 

을 지금은 주소를 가지고가는 경우 'A', 그 주소를 역 참조, 유형이 변경되지 않는의 ('주소를 복용'때문에 내 마음에, 내가 정말 좋아하는와 '역 참조'입니다 역 동작) : 그러나 나는 derefere 경우

cout<<typeid(*&a).name(); // also prints 'A3_i' 

nce 'a'를 먼저 입력 한 후 그 주소를 가져 가면 으로 변경됩니다 (내가 선호하는 배열을 역 참조 할 때 내가 int를 가져야하고 주소를 취할 때 내가 마음에 들지 않습니다. 그 INT, 나는 포인터 - 투 - INT를 받아야하고, 밝혀 I)가 수행

1) 배열 형이로 붕괴되면 : 그래서 여기

cout<<typeid(&*a).name(); // prints 'Pi' 

내 두 가지 질문 있습니다 pointer-type, 어쨌든 배열 타입으로 되돌릴 수 있습니까?

cout<<typeid((int[3]) &*a).name(); // does not compile 
// "error: ISO C++ forbids casting to an array type `int [3]'" 

일하는 것이 다른 캐스트가 있습니까 :

나는 주조와 같은 - 당신 - 방금 본건 케어의 분명한 전략을 시도? 또는이 유형의 변환은 엄격히 제한을 벗어나는 것입니까?

2) 배열 유형으로 되돌아 갈 수 있는지 여부에 관계없이 정확히 감추어 져있는 포인터 정보에서 슬라이스되고 손실되는 정보는 무엇입니까?

포인터 유형과 배열 유형이 동일하지 않다는 것을 알고 있습니다. 필자는 배열 타입이 포인터 타입에 저장된 정보의 엄격한 수퍼 셋이라고 가정합니다. 이 말이 맞습니까?

배열 형식의 추가 정보는 다음과 같습니다. 배열이 스택에 있는지 여부와 배열의 크기에 대한 정보 (배열의 크기를 어떻게 든 알고 있어야합니다. 유형의 일부입니다. 맞습니까?). 어레이 유형에 숨겨진 다른 정보가 있습니까?

+0

int []는 형식이지만 int [3]은 형식이 아닙니다. –

+4

@Daniel : "3 ints의 배열"은 "int []"와 분명히 다르며 "int [3]"은 전자의 합리적인 속기처럼 보입니다. –

+0

뭐라하던간에. –

답변

10

만약 당신이 찾고있는 것이 확실하지는 않지만 typecasting을 사용하여 원래 배열과 같은 유형의 객체를 얻을 수 있습니다. 아이디어는 정보를 복구하기 위해 거의 알려지지 않은 유형의 포인터 - 배열 및 참조 - 배열을 사용하는 것입니다. 예를 들어

char arr[137]; 
cout << sizeof(arr) << endl; // Prints 137 
cout << sizeof(arr[0]) << endl; // Prints 1 
cout << sizeof(&arr[0]) << endl; // Prints 4 (on my system) 
cout << sizeof(*&arr[0]) << endl; // Prints 1 
cout << sizeof((char (&) [137]) *&arr[0]) << endl; // Prints 137 

아이디어는 우리 char (&)[137] 137 개 문자의 배열에 대한 레퍼런스를 입력 *&arr[0]를 이용하여 생성 된 참조 캐스트이다. 이 유형의 참조가 있으므로 sizeof 연산자는 137 자의 배열 크기가 실제로 137이므로 137을 인쇄해야한다는 것을 알고 있습니다.

그러나 올바른 유형으로 유형 변환하면이 기능이 작동합니다! 예를 들어,이 완벽하게 합법적이다 :

char arr[137]; 
cout << sizeof((char (&) [42]) *&arr[0]) << endl; // Prints 42 

그래서 당신은 정보를 복구 할 수 있지만, 당신은 쉽게 그 정보가 잘못하고 잘못된 정보를 복구 한 경우에 발생할 수 있습니다.

다시 말하지만, 이것이 사용자가 찾고자하는 것인지 확실하지 않지만 실제로 배열 크기 정보를 얻기 위해 캐스팅을 사용할 수 있음을 보여줍니다.

+1

하지만 당신이 듣고 싶은 것을 캐스팅에게 말하고 있는게 아닌가요? 또한 & * a (배열 유형을 포인터 유형으로 변경하는 유형을 야기 함) 컴포지션 * 및 (배열 유형을 변경하지 않음)이 아닌 & * a의 조합에 대해 작업하고 싶습니다. – Jimmy

+0

@ Jimmy- 당신은 절대적으로 옳습니다. 이것은 배열의 크기를 알려주므로 "당신이 찾고있는 것이 확실하지 않습니다." '& * a'의 경우, 캐스트'(T (*) [size]) & * a'를 사용하여 원래 크기 인 BTW를 배열에 알릴 수 있습니다. 나는 일반적으로 이것을 수행 할 수없고 배열 크기가 사라지면 사라 졌다고 확신하지만, 크기가 무엇인지에 대한 특별한 지식이있는 경우에는 내가 가지고있는 것이 맞다고 생각합니다. – templatetypedef

+0

깔끔합니다. 내가 시도 할 때 : cout << typeid ((int (*) [3]) & * a) .name() << endl; // PA3_i ...을 출력합니다.이 포인터는 원하는 타입의 포인터입니다. 그래서 다음과 같이 시도했습니다 : cout << typeid (* (int (*) [3]) & * a) .name() << endl ; // A3_i ...를 인쇄합니다. 나는 파싱의 순서를 이해하지 못한다. (타입이 실제로 없어 졌는지는 알 수 없으므로) 나는 긍정적 인 첫 번째 질문에 대답한다고 생각한다. 두 번째 질문에 대한 어떤 생각? 추신. 왜 내가 실제로 int (*)를이 주석에 입력했을 때 int()를 보여줄지 모르겠다. ... – Jimmy

3

이 질문에 대한 완전한 대답 아니지만, 여기에 내가 제공하는 기능 - 내가이 포인터에 부패되면 다시 배열 형식으로 얻을 수있는 방법이라고 생각하지 않습니다

.

원의 배열 형태 인 T [N]N은 배열의 요소의 개수. 일단 포인터로 쇠퇴하면 크기 정보가 손실됩니다. @ templatetypdef의 answer이 보여 주듯이 포인터를 배열 유형으로 다시 캐스팅 할 수 있습니다.하지만 그는 캐스팅을 통해 컴파일러에게 크기가 무엇인지 알려주고 실제로 그 정보를 추론 할 방법이 없다는 것을 증명합니다 포인터에서.

원래 형식 정보를 유지하려면 포인터 대신 참조로 배열을 전달해야합니다.

#include <iostream> 
#include <typeinfo> 

template<size_t N> 
void ByRef(int(&array)[N]) 
{ 
    std::cout << typeid(array).name() << std::endl; 
} 

void ByPointer(int *array) 
{ 
    std::cout << typeid(array).name() << std::endl; 
    std::cout << typeid((int(&)[4])array).name() << std::endl; 
    std::cout << typeid((int(&)[42])array).name() << std::endl; 
} 

int main() 
{ 
    int a[4] = {1,2,3,4}; 

    ByRef(a); 
    ByPointer(a); 

    return 0; 
} 

위의 출력은 당신이에 얻고 무엇인지

A4_i 
Pi 
A4_i 
A42_i 
2

아니라, 당신은 아무것도의 &를 취하면 당신이 가진 전부는 주소입니다. 그리고 단순한 객체가 아닌 데이터 구조에는 설명자가 없기 때문에 주소가 주어지면 주소가 무엇이든간에 더 많은 정보를 얻을 수있는 방법이 없습니다. 예를 들어 char을 처리하는 경우에도 포인터 유형에 의해서만 전달됩니다. void*으로 캐스팅하면 해당 정보가 손실됩니다 (존재 한도까지).

나는 포인터 유형과 배열 유형이 동일하지 않다는 것을 알고 있습니다. 필자는 배열 타입이 포인터 타입에 저장된 정보의 엄격한 수퍼 셋이라고 가정합니다. 이 말이 맞습니까?

정보가 유형에 "저장되지 않았습니다. 정보 (런타임에 존재하는 경우)는 변수에 저장됩니다. C/C++에는 비 객체에 대한 동적 유형 지정이 없으므로 유형에 정보가 저장되지 않을뿐만 아니라 유형 정보가 어디에도 저장되지 않습니다. 유형 정보는 순전히 컴파일 시간 개념이며 컴파일러에 의한 정적 분석의 결과로 프로그램의 한 지점에서 다른 지점으로 "흐릅니다". 즉, 그것은 편리한 픽션입니다.

+1

나는 당신의 설명을 이해한다고 믿습니다. 내가 '타입 정보'라고 부르는 것은 컴파일러가 제대로 작동하도록하는 스펙 일뿐입니다. 따라서 배열 유형의 '추가 정보'는 컴파일 타임에 수행되는 추가 검사 (즉, 포인터 유형이 반드시 필요하지는 않은 컴파일 시간 검증)에 불과합니다. – Jimmy

+0

다형성 클래스 용으로 활성화하지 않거나 처음에 다형성을 구현하는 데 사용한 항목을 계산하지 않는 한 런타임 유형 정보가 없습니다. 그러나 컴파일 타임 형식 정보는 "추가 검사"이상의 기능을 수행합니다. 배열은 포인터가 아닙니다. 'int x [3]'는 개념적으로, 주소가 수요에 따라 계산 될 수있는 3 개의 정수 블록 (붕괴 과정)을 위해 스택에 메모리를 할당한다. 'int * x'는 개념적으로 주소의 스택에 메모리를 할당한다. **의 주소 **를 지정하지 않는다. –

+0

지미, 네가 가진 것 같아. 대부분의 컴퓨터에서는 비트 그룹이 포인터인지 여부, 정수, 문자 그룹 또는 기타 항목인지 여부를 알 수있는 방법조차 없습니다. "성능 기반"이며 다른 데이터와 포인터를 구별 할 수있는 방법이있는 몇 가지 기계 (IBM iSeries만이 여전히 만들어져 있습니다.)가 있습니다. 또한 유형에 대한 런타임 실마리가 있습니다), 그러나 이것들은 확실한 예외이다. –

관련 문제