'긴'금지가 의미가 있습니까?


109

오늘날의 크로스 플랫폼 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 등은 아닙니다)


아마도 흥미로운 배경 링크 :


14
오래 사용하는 라이브러리 호출을 어떻게 처리 할 것인가?
Ángel

14
long32 비트를 보장하는 유일한 방법입니다. int16 비트가 될 수 있으므로 일부 응용 프로그램에서는 충분하지 않습니다. 예, int최신 컴파일러에서는 때때로 16 비트입니다. 예, 사람들은 마이크로 컨트롤러에서 소프트웨어를 작성합니다. 나는 Arduinos 등의 상승을 언급하지 않고 iPhone 및 Android 기기의 등장으로 PC보다 마이크로 컨트롤러에 더 많은 사용자가있는 소프트웨어를 작성하는 사람들이 더 많다고 주장합니다.
slebetman

53
char, short, int, long 및 long long을 금지하고 [u] intXX_t 유형을 사용하지 않으시겠습니까?
immibis

7
@slebetman 나는 조금 더 깊이 파고 들었다. C ++ 표준은 다음과 같이 §3.9.1.3에 숨겨져 있지만 요구 사항이 여전히 존재하는 것으로 보인다. 4.2.1. " 그리고 C 표준 §5.2.4.2.1에서는 사용자가 작성한대로 최소 범위를 명시합니다. 당신은 절대적으로 옳았습니다. :) 분명히 C ++ 표준의 사본을 소유하는 것으로 충분하지 않습니다 .C 표준의 사본도 찾아야합니다.
Tommy Andersen

11
int여전히 16 비트 인 DOSBox / Turbo C ++ 환경이 없습니다 . 나는 그것을 말하기 싫지만, "오늘날의 크로스 플랫폼 세계"에 대해 글을 쓰려고한다면 인도 대륙 전체를 무시할 수는 없습니다.
궤도에서 가벼움 경주

답변:


17

내가 long오늘 사용하는 유일한 이유 는 그것을 사용하는 외부 인터페이스를 호출하거나 구현할 때입니다.

당신이 말한 것처럼 짧고 int는 오늘날 모든 주요 데스크탑 / 서버 / 모바일 플랫폼에서 상당히 안정적인 특성을 가지고 있으며 가까운 장래에 그것이 변할 이유가 없습니다. 그래서 나는 그것들을 일반적으로 피할 이유가 거의 없습니다.

long반면에 엉망입니다. 모든 32 비트 시스템에서 다음과 같은 특징을 알고 있습니다.

  1. 크기는 정확히 32 비트였습니다.
  2. 메모리 주소와 크기가 같습니다.
  3. 일반 레지스터에 보관할 수 있고 단일 명령으로 작업 할 수있는 가장 큰 데이터 단위와 크기가 동일했습니다.

이러한 특성 중 하나 이상을 기반으로 대량의 코드가 작성되었습니다. 그러나 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_tint와 크기가 같거나 크기 때문에 모듈로 동작이 있습니다. 그러나 역사적 int으로 64 비트이며 따라서 uint32_t모듈로 동작이없는 미래 플랫폼에는 이론적으로 존재할 수 있습니다.

개인적으로 나는 방정식의 시작 부분에 "1u *"또는 "0u +"를 사용하여 모듈러스 동작을 강제하는 습관이 더 좋을 것이라고 말하고 싶습니다.


1
모든 "지정된 크기"유형은 내장 유형과 다른 의미를 지정할 수있는 경우 훨씬 유용합니다. 예를 들어, "int"의 크기에 관계없이 mod-65536 산술을 사용하는 유형과 0에서 65535까지의 숫자를 보유 할 수 있지만 임의 적이고 일관되게 가능 하지 않을 수있는 유형을 갖는 것이 유용 합니다. 그보다 더 큰 숫자를 보유합니다. 대부분의 컴퓨터에서 가장 빠른 크기 유형은 컨텍스트에 따라 달라 지므로 컴파일러가 임의로 선택할 수있게하는 것이 속도에 가장 적합합니다.
supercat

204

귀하의 질문에서 언급했듯이 현대 소프트웨어는 인터넷의 플랫폼과 시스템 간의 상호 운용에 관한 것입니다. 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.


20
나는 이것에 대해 더 많은 투표를하기 위해 5 개의 다른 계정을 가지고 있었으면 좋겠다.
Steven Burnap

4
+1, 구조체의 크기가 컴파일하는 컴퓨터에 따라 달라지는 경우에만 발생하는 이상한 메모리 오류를 처리했습니다.
Joshua Snider

9
@Wildcard 그것은 C ++의 일부인 C 헤더입니다. "c"접두사를보십시오. C ++ 컴파일 단위로 d를 std사용할 때 네임 스페이스에 typedef를 넣을 수있는 방법도 #include있지만, 연결된 문서에는 언급하지 않았으며 Visual Studio는 액세스 방법에 신경 쓰지 않는 것 같습니다.

11
금지 int가 과도할까요? (코드가 모호하지 않은 모든 플랫폼에서 매우 이식성이 뛰어나야하는 경우이 코드를 고려할 것입니다. "앱 코드"에 대한 코드 금지는 개발자와 잘 맞지 않을 수 있습니다.
Martin Ba

5
@Snowman #include <cstdint>은 형식을 입력 해야std:: 하며 (유감스럽게도) 선택적으로 전역 네임 스페이스에도 입력 할 있습니다. #include <stdint.h>정확히 대화입니다. 다른 C 헤더 쌍에도 동일하게 적용됩니다. 참조 : stackoverflow.com/a/13643019/2757035 표준에 따라 각각의 필요한 네임 스페이스에만 영향을 미치기를 원합니다. 일부 구현에 의해 설정된 가난한 규칙에 맞지 않는 것처럼 보이지만 여기 있습니다.
underscore_d

38

아니요, 내장 정수 유형을 금지하는 것은 터무니없는 것입니다. 그러나 남용해서는 안됩니다.

너비 가 정확히 N 비트 인 정수가 필요한 경우 (또는 버전 이 필요한 경우 )를 사용하십시오. 의 생각 32 비트 정수로와 64 비트 정수로 그냥 잘못된 것입니다. 현재 플랫폼에서 이와 같을 수 있지만 구현 정의 동작에 의존합니다.std::intN_tstd::uintN_tunsignedintlong long

고정 폭 정수 유형을 사용하면 다른 기술과의 상호 운용에도 유용합니다. 예를 들어, 응용 프로그램의 일부가 Java로 작성되고 다른 일부는 C ++로 작성되는 경우 정수 유형을 일치시켜 일관된 결과를 얻을 수 있습니다. (Java의 오버플로에는 잘 정의 된 의미가 있지만 signedC ++의 오버플로는 정의되지 않은 동작이므로 일관성이 높은 목표입니다.) 또한 다른 컴퓨팅 호스트간에 데이터를 교환 할 때 매우 중요합니다.

정확히 N 비트 가 필요하지 않지만 충분히 넓은 유형이면 (공간에 최적화) 또는 (속도에 최적화 ) 사용을 고려하십시오 . 다시 말하지만, 두 가족 모두 상대방을 가지고 있습니다.std::int_leastN_tstd::int_fastN_tunsigned

그렇다면 내장 유형을 언제 사용해야합니까? 표준은 폭을 정확하게 지정 하지 않기 때문에 실제 비트 폭에 신경 쓰지 않고 다른 특성에 신경 쓰면 사용하십시오.

A char는 하드웨어가 처리 할 수있는 가장 작은 정수입니다. 이 언어는 실제로 임의 메모리의 앨리어싱에 사용하도록 강제합니다. 또한 (좁은) 문자열을 나타내는 유일한 유형입니다.

int일반적으로 기계가 처리 할 수있는 가장 빠른 유형이 될 것입니다. 단일 명령어 (비트를 마스킹하거나 시프트 할 필요없이)로로드 및 저장 될 수있을만큼 충분히 넓고 효율적인 하드웨어 명령어로 작동 될 수 있도록 충분히 좁을 것입니다. 따라서 int오버플로가 문제가되지 않을 때 데이터를 전달하고 산술을 수행하기위한 완벽한 선택입니다. 예를 들어, 기본 기본 열거 유형은입니다 int. 가능한 한 32 비트 정수로 변경하지 마십시오. 또한 값이 –1, 0 및 1 일 수있는 경우int거대한 배열을 저장하지 않는 한 완벽한 선택입니다.이 경우 개별 요소에 액세스하기 위해 더 높은 가격을 지불해야하는 비용으로 더 컴팩트 한 데이터 유형을 사용할 수 있습니다. 보다 효율적인 캐싱은 이에 대한 대가를 치를 것입니다. 많은 운영 체제 기능도로 정의됩니다 int. 그들의 주장과 결과를 앞뒤로 바꾸는 것은 어리석은 일입니다. 가능하게 할 수있는 모든이는 소개 오버플로 오류를.

long일반적으로 단일 기계 명령어로 처리 할 수있는 가장 넓은 유형입니다. 이것은 특히 unsigned long원시 데이터와 모든 종류의 비트 조작을 처리하는 데 매우 매력적입니다. 예를 들어, unsigned long비트 벡터의 구현에서 볼 수 있습니다. 코드를 신중하게 작성하면 실제로 코드의 너비가 중요하지 않습니다 (코드가 자동으로 적용되기 때문). 기본 기계어가 32 비트 인 플랫폼에서 비트 벡터의 백업 배열은 다음과 같은 배열입니다.unsigned32 비트 정수는 어쨌든 불필요한 비트를 이동하고 마스킹하기 위해 값 비싼 명령어를 통해로드되어야하는 64 비트 유형을 사용하는 것이 어리석기 때문에 가장 바람직합니다. 반면에 플랫폼의 기본 단어 크기가 64 비트 인 경우“find first set”과 같은 작업이 최대 두 배 빠르게 실행될 수 있기 때문에 해당 유형의 배열을 원합니다. 따라서 long설명하는 데이터 유형 의 "문제" 는 크기가 플랫폼마다 다르며 실제로는 잘 활용 될 수 있는 기능 입니다. 내장 유형을 특정 비트 너비의 유형으로 생각하면 문제가됩니다.

char, intlong상술 한 바와 같이 매우 유용한 형식이다. short그리고 long long그 의미가 훨씬 덜 분명하기 때문에 거의 유용하지 않습니다.


4
OP는 특히 longWindows와 Unix 의 크기 차이를 지적했습니다 . 오해가 있을지 모르지만 long"문제"대신 "기능" 의 크기 차이에 대한 설명은 32 비트 및 64 비트 데이터 모델을 비교하는 데 적합하지만이 특정 비교에는 적합하지 않습니다. 이 질문에 대한 특별한 경우에 이것이 실제로 기능입니까? 아니면 다른 상황 (즉, 일반적으로)의 특징이며이 경우 무해합니까?
Dan Getz

3
@ 5gon12eder : 문제는 코드의 동작이 "int"의 크기와 무관하게되도록 uint32_t와 같은 유형이 생성되었지만 "uint32_t처럼 작동하는 32-t에서 작동하는 유형의 부족"입니다. "bit system"은 "int"의 크기와는 독립적으로 동작이 올바른 코드를 작성하는 것이 거의 정확한 코드를 작성하는 것보다 훨씬 어렵습니다.
supercat

3
응, 저주가 시작된 곳이야 원래 작성자는 코드를 작성할 때 32 비트 OS가 10 년 이상 떨어져 있기 때문에 임대 저항의 길을갔습니다.
Steven Burnap

8
슬프게도 supercat은 정확합니다. 정확한 폭의 모든 유형의는 "단지 형식 정의"및 정수 프로모션 규칙에 대한 연산을 의미 그들 중 어떤 통지 취하지 uint32_t값은 다음과 같이 진행됩니다 서명 , int플랫폼에 -width 산술 int입니다 넓은 이상을 uint32_t. (오늘날 ABI에서는이 문제가 압도적으로 더 큰 문제가 될 가능성이 높습니다 uint16_t.)
zwol

9
첫째, 자세한 답변 주셔서 감사합니다. 그러나 : 오 이런. 긴 단락 : " long일반적으로 단일 기계 명령어로 처리 할 수있는 가장 넓은 유형입니다. ..."-이것은 정확히 잘못되었습니다 . Windows 데이터 모델을보십시오. IMHO, x64 Windows long은 여전히 ​​32 비트이기 때문에 다음 예제가 모두 나뉩니다.
Martin Ba

6

또 다른 대답은 이미 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경우 계속 확인됩니다.


왜 downvote (댓글없이)입니까?
JDługosz

이 네트워크에있는 대부분의 downvotes는 설명없이 나타납니다 ...
Ruslan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.