오늘날의 크로스 플랫폼 C ++ (또는 C) 세계 에는 다음 이 있습니다 .
Data model | short | int | long | long long | pointers/size_t | Sample operating systems
...
LLP64/IL32P64 16 32 32 64 64 Microsoft Windows (x86-64 and IA-64)
LP64/I32LP64 16 32 64 64 64 Most Unix and Unix-like systems, e.g. Solaris, Linux, BSD, and OS X; z/OS
...
이것이 오늘날 의미하는 바는 “공통”(부호있는) 정수의 int
경우 C ++ 응용 프로그램 코드를 작성할 때 기본 정수 유형으로 사용될 수 있다는 것입니다. 또한 현재의 실제적인 목적으로 여러 플랫폼에서 일관된 크기를 갖습니다.
유스 케이스에 64 비트 이상이 필요한 경우 비트리스 지정 유형long long
중 하나를 사용 하거나 유형이 더 적합 할 수 있지만 오늘 사용할 수 있습니다 .__int64
이것은 long
중간에 남았으며 long
우리는 응용 프로그램 코드에서 사용을 금지하는 것을 고려하고 있습니다 .
이것이 합리적입니까 , 아니면 long
크로스 플랫폼을 실행 해야하는 최신 C ++ (또는 C) 코드에서 사용하는 경우 가 있습니까? (플랫폼은 데스크톱, 모바일 기기이지만 마이크로 컨트롤러, DSP 등은 아닙니다)
아마도 흥미로운 배경 링크 :
- C ++ 표준은 int, long 유형의 크기를 무엇이라고 말합니까?
- Win64 팀이 LLP64 모델을 선택한 이유는 무엇입니까?
- 64 비트 프로그래밍 모델 : 왜 LP64인가? (어떤 나이 든)
- 되어
long
최소한 32 비트 보장? (이것은 아래의 의견 토론을 다룹니다. 답변 .)
답변
내가 long
오늘 사용하는 유일한 이유 는 그것을 사용하는 외부 인터페이스를 호출하거나 구현할 때입니다.
당신이 말한 것처럼 짧고 int는 오늘날 모든 주요 데스크탑 / 서버 / 모바일 플랫폼에서 상당히 안정적인 특성을 가지고 있으며 가까운 장래에 그것이 변할 이유가 없습니다. 그래서 나는 그것들을 일반적으로 피할 이유가 거의 없습니다.
long
반면에 엉망입니다. 모든 32 비트 시스템에서 다음과 같은 특징을 알고 있습니다.
- 크기는 정확히 32 비트였습니다.
- 메모리 주소와 크기가 같습니다.
- 일반 레지스터에 보관할 수 있고 단일 명령으로 작업 할 수있는 가장 큰 데이터 단위와 크기가 동일했습니다.
이러한 특성 중 하나 이상을 기반으로 대량의 코드가 작성되었습니다. 그러나 64 비트로 전환하면 모든 것을 보존 할 수 없었습니다. Unix와 유사한 플랫폼은 특성 1의 비용으로 특성 2와 3을 보존하는 LP64를 사용했습니다. Win64는 특성 2와 3의 비용으로 특성 1을 보존하는 LLP64를 사용했습니다. 결과적으로 더 이상 해당 특성에 의존 할 수 없습니다 IMO는 사용할 이유가 거의 없습니다 long
.
크기가 정확히 32 비트 인 유형을 원하면을 사용해야합니다 int32_t
.
포인터와 크기가 같은 유형을 원하면 intptr_t
(또는 더 나은 uintptr_t
) 사용해야합니다 .
단일 레지스터 / 지침에서 작업 할 수있는 가장 큰 항목 인 유형을 원한다면 불행히도 표준이 하나를 제공한다고 생각하지 않습니다. size_t
가장 일반적인 플랫폼에 적합하지만 x32에 있지 않습니다 .
추신
나는 “빠른”또는 “최소”유형을 신경 쓰지 않을 것입니다. “최소”유형은 아키텍처를 모호하게 만드는 이식성에 관심이있는 경우에만 중요합니다 CHAR_BIT != 8
. 실제로 “빠른”유형의 크기는 꽤 임의적 인 것 같습니다. Linux는 x86-64 및 arm64와 같은 빠른 32 비트 지원 64 비트 플랫폼에서 바보 같은 포인터 크기 이상을 만드는 것 같습니다. IIRC iOS는 가능한 작게 만듭니다. 다른 시스템의 기능이 확실하지 않습니다.
PPS
사용하는 한 가지 이유는 unsigned long
(단순하지는 않지만 long
) 모듈로 동작을 보장하기 때문입니다. 불행히도 C의 조율 규칙으로 인해 int
모듈 식 동작이없는 것보다 작은 부호없는 유형 이 있습니다.
오늘날 모든 주요 플랫폼에서 uint32_t
int와 크기가 같거나 크기 때문에 모듈로 동작이 있습니다. 그러나 역사적 int
으로 64 비트이며 따라서 uint32_t
모듈로 동작이없는 미래 플랫폼에는 이론적으로 존재할 수 있습니다.
개인적으로 나는 방정식의 시작 부분에 “1u *”또는 “0u +”를 사용하여 모듈러스 동작을 강제하는 습관이 더 좋을 것이라고 말하고 싶습니다.
답변
귀하의 질문에서 언급했듯이 현대 소프트웨어는 인터넷의 플랫폼과 시스템 간의 상호 운용에 관한 것입니다. C 및 C ++ 표준은 Java 및 C #과 같은 언어와 달리 특정 크기가 아닌 정수 유형 크기의 범위 를 제공 합니다 .
다른 플랫폼에서 컴파일 된 소프트웨어가 동일한 데이터와 동일한 방식으로 작동하기 위해서는 및 기타 소프트웨어는 소프트웨어가 같은 크기와 상호 작용할 수 있도록, 당신은 고정 된 크기의 정수를 사용해야합니다.
<cstdint>
정확하게 입력 하고 모든 컴파일러 및 표준 라이브러리 플랫폼이 제공해야하는 표준 헤더 인 Enter 를 입력하십시오 . 참고 :이 헤더는 C ++ 11부터 필요했지만 많은 오래된 라이브러리 구현에서 제공했습니다.
부호없는 64 비트 정수를 원하십니까? 사용하십시오 uint64_t
. 부호있는 32 비트 정수? 사용하십시오 int32_t
. 헤더의 유형은 선택 사항이지만 최신 플랫폼은 해당 헤더에 정의 된 모든 유형을 지원해야합니다.
예를 들어 다른 시스템과의 통신에 사용되는 데이터 구조에서 특정 비트 폭이 필요할 수도 있습니다. 다른 때는 그렇지 않습니다. 덜 엄격한 상황 <cstdint>
에서는 최소 너비 인 유형을 제공하십시오.
최소 변형 은 다음과 같습니다 int_leastXX_t
. 최소 XX 비트의 정수 유형입니다. XX 비트를 제공하는 가장 작은 유형을 사용하지만 유형이 지정된 비트 수보다 클 수 있습니다. 실제로, 이들은 일반적으로 정확한 수의 비트를 제공하는 위에서 설명한 유형과 동일합니다.
도 있습니다 빠른 변종 : int_fastXX_t
적어도 XX 비트, 특정 플랫폼에 빠르게 수행하는 형식을 사용해야합니다. 이 문맥에서 “빠른”의 정의는 지정되어 있지 않습니다. 그러나 실제로 이것은 일반적으로 CPU의 레지스터 크기보다 작은 유형이 CPU의 레지스터 크기 유형과 별명 일 수 있음을 의미합니다. 예를 들어 Visual C ++ 2015의 헤더 int_fast16_t
는 32 비트 산술이 16 비트 산술보다 x86에서 전체적으로 더 빠르기 때문에 32 비트 정수임을 지정합니다 .
이는 플랫폼에 관계없이 프로그램이 수행하는 계산 결과를 보유 할 수있는 유형을 사용할 수 있어야하기 때문에 모두 중요합니다. 정수 오버플로의 차이로 인해 프로그램이 한 플랫폼에서 올바른 결과를 생성하지만 다른 플랫폼에서는 잘못된 결과를 생성하면 좋지 않습니다. 표준 정수 유형을 사용하면 사용되는 정수 의 크기와 관련하여 다른 플랫폼의 결과가 동일하게 보장 됩니다 (물론 정수 너비 이외의 플랫폼간에 다른 차이가있을 수 있음).
따라서 long
현대적인 C ++ 코드에서 금지되어야합니다. 이렇게해야 int
, short
하고 long long
.
답변
아니요, 내장 정수 유형을 금지하는 것은 터무니없는 것입니다. 그러나 남용해서는 안됩니다.
너비 가 정확히 N 비트 인 정수가 필요한 경우 (또는 버전 이 필요한 경우 )를 사용하십시오. 의 생각 32 비트 정수로와 64 비트 정수로 그냥 잘못된 것입니다. 현재 플랫폼에서 이와 같을 수 있지만 구현 정의 동작에 의존합니다.std::intN_t
std::uintN_t
unsigned
int
long long
고정 폭 정수 유형을 사용하면 다른 기술과의 상호 운용에도 유용합니다. 예를 들어, 응용 프로그램의 일부가 Java로 작성되고 다른 일부는 C ++로 작성되는 경우 정수 유형을 일치시켜 일관된 결과를 얻을 수 있습니다. (Java의 오버플로에는 잘 정의 된 의미가 있지만 signed
C ++의 오버플로는 정의되지 않은 동작이므로 일관성이 높은 목표입니다.) 또한 다른 컴퓨팅 호스트간에 데이터를 교환 할 때 매우 중요합니다.
정확히 N 비트 가 필요하지 않지만 충분히 넓은 유형이면 (공간에 최적화) 또는 (속도에 최적화 ) 사용을 고려하십시오 . 다시 말하지만, 두 가족 모두 상대방을 가지고 있습니다.std::int_leastN_t
std::int_fastN_t
unsigned
그렇다면 내장 유형을 언제 사용해야합니까? 표준은 폭을 정확하게 지정 하지 않기 때문에 실제 비트 폭에 신경 쓰지 않고 다른 특성에 신경 쓰면 사용하십시오.
A char
는 하드웨어가 처리 할 수있는 가장 작은 정수입니다. 이 언어는 실제로 임의 메모리의 앨리어싱에 사용하도록 강제합니다. 또한 (좁은) 문자열을 나타내는 유일한 유형입니다.
은 int
일반적으로 기계가 처리 할 수있는 가장 빠른 유형이 될 것입니다. 단일 명령어 (비트를 마스킹하거나 시프트 할 필요없이)로로드 및 저장 될 수있을만큼 충분히 넓고 효율적인 하드웨어 명령어로 작동 될 수 있도록 충분히 좁을 것입니다. 따라서 int
오버플로가 문제가되지 않을 때 데이터를 전달하고 산술을 수행하기위한 완벽한 선택입니다. 예를 들어, 기본 기본 열거 유형은입니다 int
. 가능한 한 32 비트 정수로 변경하지 마십시오. 또한 값이 –1, 0 및 1 일 수있는 경우int
거대한 배열을 저장하지 않는 한 완벽한 선택입니다.이 경우 개별 요소에 액세스하기 위해 더 높은 가격을 지불해야하는 비용으로 더 컴팩트 한 데이터 유형을 사용할 수 있습니다. 보다 효율적인 캐싱은 이에 대한 대가를 치를 것입니다. 많은 운영 체제 기능도로 정의됩니다 int
. 그들의 주장과 결과를 앞뒤로 바꾸는 것은 어리석은 일입니다. 가능하게 할 수있는 모든이는 소개 오버플로 오류를.
long
일반적으로 단일 기계 명령어로 처리 할 수있는 가장 넓은 유형입니다. 이것은 특히 unsigned long
원시 데이터와 모든 종류의 비트 조작을 처리하는 데 매우 매력적입니다. 예를 들어, unsigned long
비트 벡터의 구현에서 볼 수 있습니다. 코드를 신중하게 작성하면 실제로 코드의 너비가 중요하지 않습니다 (코드가 자동으로 적용되기 때문). 기본 기계어가 32 비트 인 플랫폼에서 비트 벡터의 백업 배열은 다음과 같은 배열입니다.unsigned
32 비트 정수는 어쨌든 불필요한 비트를 이동하고 마스킹하기 위해 값 비싼 명령어를 통해로드되어야하는 64 비트 유형을 사용하는 것이 어리석기 때문에 가장 바람직합니다. 반면에 플랫폼의 기본 단어 크기가 64 비트 인 경우“find first set”과 같은 작업이 최대 두 배 빠르게 실행될 수 있기 때문에 해당 유형의 배열을 원합니다. 따라서 long
설명하는 데이터 유형 의 “문제” 는 크기가 플랫폼마다 다르며 실제로는 잘 활용 될 수 있는 기능 입니다. 내장 유형을 특정 비트 너비의 유형으로 생각하면 문제가됩니다.
char
, int
및 long
상술 한 바와 같이 매우 유용한 형식이다. short
그리고 long long
그 의미가 훨씬 덜 분명하기 때문에 거의 유용하지 않습니다.
답변
또 다른 대답은 이미 cstdint 유형과 그에 덜 알려진 변형에 대해 자세히 설명합니다.
나는 그것에 추가하고 싶습니다 :
도메인 별 유형 이름 사용
즉 수 있도록 매개 변수와 변수를 선언하지 않는 것입니다 uint32_t
(확실히 long
같은 이름!)하지만 channel_id_type
, room_count_type
등
도서관에 대하여
long
특히 사용하거나 참조하지 않는 타사 라이브러리는 성가신 것일 수 있습니다.
가장 좋은 점은 래퍼를 만드는 것입니다.
내 전략은 일반적으로 사용될 캐스트와 같은 함수 세트를 만드는 것입니다. 필요한 포인터 등의 변형과 함께 해당 유형과 정확히 일치하는 유형 만 허용하도록 오버로드됩니다. 이들은 os / 컴파일러 / 설정에 따라 정의됩니다. 이를 통해 경고를 제거하고 “올바른”변환 만 사용되도록 할 수 있습니다.
channel_id_type cid_out;
...
SomeLibFoo (same_thing_really<int*>(&cid_out));
특히, 32 비트를 생성하는 다른 기본 유형의 int32_t
경우 정의 된 방법 선택은 라이브러리 호출과 일치하지 않을 수 있습니다 (예 : Windows의 int vs long).
캐스트와 유사한 함수 는 충돌을 문서화 하고 함수의 매개 변수와 일치하는 결과에 대한 컴파일 타임 검사를 제공 하며 실제 유형이 실제 크기와 일치하는 경우에만 경고 또는 오류를 제거합니다 . 즉, Windows에서 int*
a 또는 a를 전달하면 오버로드되고 정의되며 long*
그렇지 않으면 컴파일 타임 오류가 발생합니다.
따라서 라이브러리가 업데이트되거나 누군가가 변경 한 channel_id_type
경우 계속 확인됩니다.