기존 코드를 64 비트 시스템에 적용하려고합니다. 주요 문제는 한 함수에서 이전 코더가 함수 자체에서 적합한 유형으로 변환되는 void * 인수를 사용한다는 것입니다. 간단한 예 :
void function(MESSAGE_ID id, void* param)
{
if(id == FOO) {
int real_param = (int)param;
// ...
}
}
물론 64 비트 컴퓨터에서는 오류가 발생합니다.
error: cast from 'void*' to 'int' loses precision
32 비트 컴퓨터에서 가능한 한 깔끔하게 작동하도록이 문제를 수정하고 싶습니다. 어떤 생각?
답변
사용 intptr_t
하고 uintptr_t
.
이식 가능한 방식으로 정의되도록하려면 다음과 같은 코드를 사용할 수 있습니다.
#if defined(__BORLANDC__)
typedef unsigned char uint8_t;
typedef __int64 int64_t;
typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef __int64 int64_t;
#else
#include <stdint.h>
#endif
.h 파일에 넣고 필요한 곳에 포함하면됩니다.
또는 여기stdint.h
에서 Microsoft 버전의 파일을 다운로드 하거나 여기 에서 휴대용 파일을 사용할 수 있습니다 .
답변
이것이 현대적인 C ++ 방식이라고 말하고 싶습니다.
#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);
수정 :
정수에 대한 올바른 유형
따라서 포인터를 정수로 저장하는 올바른 방법은 uintptr_t
또는 intptr_t
유형 을 사용하는 것 입니다. ( C99에 대한 cppreference 정수 유형 참조 ).
이러한 유형은 <stdint.h>
C99 및 std
C ++ 11 의 네임 스페이스 에 정의되어 있습니다 <cstdint>
( C ++의 정수 유형 참조 ).
C ++ 11 (이상) 버전
#include <cstdint>
std::uintptr_t i;
C ++ 03 버전
extern "C" {
#include <stdint.h>
}
uintptr_t i;
C99 버전
#include <stdint.h>
uintptr_t i;
올바른 캐스팅 연산자
C에서는 캐스트가 하나 뿐이며 C ++에서 C 캐스트를 사용하는 것은 눈살을 찌푸립니다 (따라서 C ++에서는 사용하지 마십시오). C ++에는 다른 캐스트가 있습니다. reinterpret_cast
이 변환에 대한 올바른 캐스트입니다 ( 여기 참조 ).
C ++ 11 버전
auto i = reinterpret_cast<std::uintptr_t>(p);
C ++ 03 버전
uintptr_t i = reinterpret_cast<uintptr_t>(p);
C 버전
uintptr_t i = (uintptr_t)p; // C Version
관련 질문
답변
아키텍처와 일치하려면 ‘size_t’및 ‘ptrdiff_t’가 필요합니다. 따라서 ‘int’를 사용하는 것보다 64 비트 시스템에서 64 비트 유형이어야하는 ‘size_t’를 사용할 수 있어야한다고 생각합니다.
이 토론 unsigned int 대 size_t 는 좀 더 자세히 설명합니다.
답변
uintptr_t
정수 유형으로 사용하십시오 .
답변
여러 답변에서 지적 uintptr_t
하고#include <stdint.h>
‘는’솔루션으로. 즉, 답변의 일부이지만 전체 답변은 아닙니다. 또한 FOO의 메시지 ID로 함수가 호출되는 위치를 확인해야합니다.
이 코드와 컴파일을 고려하십시오.
$ cat kk.c
#include <stdio.h>
static void function(int n, void *p)
{
unsigned long z = *(unsigned long *)p;
printf("%d - %lu\n", n, z);
}
int main(void)
{
function(1, 2);
return(0);
}
$ rmk kk
gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
-Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$
호출 위치 (in main()
)에 문제가 있음을 알 수 있습니다. 캐스트없이 정수를 포인터로 변환합니다. function()
값이 전달되는 방식을 확인하려면 모든 용도를 분석해야 합니다. function()
호출이 작성되면 내 코드 가 작동합니다.
unsigned long i = 0x2341;
function(1, &i);
당신의 것들은 아마도 다르게 쓰여질 것이므로, 표시된대로 값을 사용하는 것이 합리적인지 확인하기 위해 함수가 호출되는 지점을 검토해야합니다. 잊지 마세요. 잠재적 인 버그를 발견 할 수 있습니다.
또한이 값의 형식을하려는 경우, void *
매개 변수 (변환 등)에주의 깊게 살펴 <inttypes.h>
헤더 (대신 stdint.h
– inttypes.h
의 서비스를 제공하는 stdint.h
특별한이다,하지만 C99 표준은 말한다 그는 헤더는 [t] <inttypes.h>
헤더를 포함 <stdint.h>
하고 호스팅 된 구현에서 제공하는 추가 기능으로 확장하고 형식 문자열에 PRIxxx 매크로를 사용합니다.
또한 내 의견은 C ++가 아닌 C에 엄격하게 적용되지만 코드는 C와 C ++간에 이식 가능한 C ++의 하위 집합에 있습니다. 내 의견이 적용될 가능성은 공평합니다.
답변
#include <stdint.h>
uintptr_t
포함 된 표준 헤더 파일에 정의 된 표준 유형을 사용하십시오 .
답변
SQLite 의 소스 코드를 연구하는 동안이 질문을 보았습니다 .
에서 sqliteInt.h , 정수와 포인터 사이 매크로 변환을 정의 된 코드의 단락이있다. 저자는 먼저 컴파일러에 의존적 인 문제가되어야한다고 지적한 다음 대부분의 인기있는 컴파일러를 설명하는 솔루션을 구현했습니다.
#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
#else /* Generates a warning - but it always works */
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
자세한 내용은 다음과 같은 의견을 인용합니다.
/*
** The following macros are used to cast pointers to integers and
** integers to pointers. The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
**
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
** So we have to define the macros in different ways depending on the
** compiler.
*/
크레딧은 커미터에게갑니다.