다른 컴파일러에서 void **로 변환


9

다른 컴파일러를 통해 다음 코드를 실행했습니다.

int main()
{
    float **a;
    void **b;
    b = a;
}

내가 수집 할 수 있었던 것은 일반적인 포인터 void **아니기 때문에 다른 포인터에서 변환 할 때 컴파일하거나 적어도 경고를 보내서는 안됩니다. 그러나 내 결과는 다음과 같습니다 (모두 Windows에서 수행됨).

  • gcc- 예상대로 경고를 던집니다.
  • g ++ -예상대로 오류가 발생합니다 (C ++의 덜 관용적 인 타이핑 때문입니까?)
  • MSVC (cl.exe) -/ Wall을 지정해도 경고가 발생하지 않습니다.

내 질문은 : 나는 모든 것에 대해 뭔가를 놓치고 MSVC가 경고를 생성하지 않는 특별한 이유가 있습니까? 에서 로 변환 할 때 MSVC 경고를 생성 함 void **float ** .

또 다른 참고 사항 : a = b명시 적 변환으로 교체하면a = (void **)b 으로 바꾸면 어떤 컴파일러도 경고를 던지지 않습니다. 나는 이것이 잘못된 캐스트라고 생각했는데 왜 경고가 없습니까?

내가이 질문을하는 이유는 CUDA를 배우기 시작했고 공식 프로그래밍 안내서 ( https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory ) 에서 시작했기 때문입니다. 다음 코드를 찾을 수 있습니다 :

// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);

이는 암시 적 변환을 수행해야 void **위한 &d_A첫 번째 인수로서, cudaMalloc타입이다 void **. 문서 전체에서 비슷한 코드를 찾을 수 있습니다. 이것은 NVIDIA의 끝에서 부주의 한 작업입니까? 아니면 다시 누락 된 것입니까? nvccMSVC를 사용 하므로 코드가 경고없이 컴파일됩니다.


3
게시 된 3 라이브의 오류 : godbolt.org/z/GQWMNo
Richard Critten

3
MSVC에서 코드 오류가 발생했습니다. 어떤 버전을 사용하고 있습니까? 그러나 네, void**일반적인 포인터가 아닙니다. 만 void*입니다.
NathanOliver

빠른 답변 감사합니다! x64의 경우 19.24.28315는 분명히? 전에는 MSVC를 사용하지 않았습니다.
CaptainProton42

2
(void**)명시적인 c 스타일 캐스트입니다. 컴파일러가 수행중인 작업을 자세히 보지 말고 신뢰하도록 지시합니다. 유형 안전 시스템을 명시 적으로 재정의하고 컴파일러는 기본적으로 모든 종류의 변환을 허용해야합니다. C 스타일 캐스트는 피해야합니다. 너무 강력합니다. static_cast말이 안되는 일을하려고하면 불평 할 것 같은 C ++ 캐스트를 사용하십시오 .
François Andrieux

@RichardCritten 잘못된 언어-오류 없음 godbolt.org/z/RmFpgN C ++ cuda에는 일반적으로 명시적인 캐스트가 필요합니다.
P__J__

답변:


4

전체에 대해 뭔가를 놓치고 MSVC가 경고를 생성하지 않는 특별한 이유가 있습니까? void **에서 float **로 변환 할 때 MSVC가 경고를 생성 함

캐스트가없는 이러한 할당은 제약 조건 위반이므로 표준 호환 컴파일러는 경고 또는 오류를 인쇄합니다. 그러나 MSVC는 C를 완벽하게 준수하지 않습니다.

또 다른 참고 사항 : a = b를 명시 적 변환 a = (void **) b로 바꾸면 컴파일러 중 어느 것도 경고를 던지지 않습니다. 나는 이것이 잘못된 캐스트라고 생각했는데 왜 경고가 없습니까?

캐스트를 통한 포인터 변환은 일부 상황에서 허용됩니다. C 표준은 섹션 6.3.2.3p7에서 다음과 같이 말합니다.

객체 유형에 대한 포인터는 다른 객체 유형에 대한 포인터로 변환 될 수 있습니다. 결과 포인터가 참조 된 유형에 맞게 올바르게 정렬되지 않으면 동작이 정의되지 않습니다. 그렇지 않으면, 다시 변환 될 때 결과는 원래 포인터와 동일하게 비교됩니다. 객체에 대한 포인터가 문자 유형에 대한 포인터로 변환되면 결과는 객체의 주소가 가장 낮은 바이트를 가리 킵니다. 객체의 크기까지 결과의 연속적인 증가는 객체의 나머지 바이트에 대한 포인터를 생성합니다.

그래서 당신 수 있습니다 정렬 문제가없고 대상이 (이 아닌 경우) 만 변환하면 포인터 유형간에 변환char * .

float* d_A;
cudaMalloc(&d_A, size);

...

이것은 NVIDIA의 끝에서 부주의 한 작업입니까? 아니면 다시 누락 된 것입니까?

아마도이 함수는 주어진 포인터를 참조하지 않고 할당 된 일부 메모리의 주소를 쓰는 것입니다. 그것은 float *마치 마치 마치 에 쓰는 것을 의미합니다 void *. 이는 로의 일반적인 전환과는 다릅니다 void *. 엄밀히 말하면, 이것은 실제 작동하지 않을 때 최신 x86 프로세서가 모든 포인터 유형에 대해 동일한 표현을 사용하기 때문에 "작동"하지만 정의되지 않은 동작처럼 보입니다.


@dbush 매우 유익한 정보입니다. 감사합니다! 작동하면 왜 작동하는지 알 수 있습니다. 그래도 &d_A필요한 유형이 없기 때문에 대부분의 컴파일러에서 경고 또는 오류가 발생 하지 않습니까?
CaptainProton42

3
이것을 어떻게 해석하는지주의하십시오. C ++ 컴파일러로 CUDA를 컴파일 할 경우 템플릿 트릭이있을 수 있습니다.
talonmies
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.