기호별 또는 크기별 유형이 아닌 "int"를 사용해야 할 때는 언제입니까?
C에 실장된 프로그래밍 언어용 작은 VM이 있습니다.32비트 아키텍처와 64비트 아키텍처 및 C++ 아키텍처 모두에서 컴파일할 수 있습니다.
가능한 한 많은 경고를 활성화하여 깔끔하게 컴파일하려고 합니다.켜면CLANG_WARN_IMPLICIT_SIGN_CONVERSION
새로운 경고 메시지가 계속 표시됩니다.
언제 사용할지 좋은 전략을 갖고 싶다.int
명시적으로 서명되지 않은 유형 및/또는 명시적으로 크기가 지정된 유형 중 하나와 비교합니다.아직까지는 어떤 전략을 세워야 할지 고민하고 있습니다.
이 둘을 혼합하는 것은 확실합니다.대부분의 경우int
로컬 변수나 파라미터와 같은 것, 구조체의 필드에 좁은 타입을 사용하는 것 등 암묵적인 변환 문제가 많이 발생합니다.
힙 내의 객체에 대한 메모리 사용량을 명시적으로 제어할 수 있기 때문에 구조 필드에 대해 보다 구체적인 크기의 유형을 사용하는 것이 좋습니다.또한 해시 테이블의 경우 해시 시 서명되지 않은 오버플로에 의존하기 때문에 해시 테이블의 크기가 다음과 같이 저장되면 좋습니다.uint32_t
.
하지만 좀 더 구체적인 타입을 쓰려고 하면 미로처럼 뒤틀린 캐스팅이 도처에 널려 있어요.
다른 C프로젝트는 무엇을 합니까?
어레이 멤버에 액세스하거나 버퍼를 제어하기 위해 사용되는 많은 수를 다음과 같이 유지합니다.size_t
.
다음을 사용하는 프로젝트의 예size_t
, GNU 의 dd.c, 155 행을 참조해 주세요.
여기 제가 하는 일이 몇 가지 있습니다.모두를 위한 건지는 모르겠지만 날 위해 일해요
- 사용 안 함
int
또는unsigned int
직접적으로.그 일에는 항상 더 적절한 이름이 붙는 타입이 있는 것 같다. - 변수가 특정 너비여야 하는 경우(예: 하드웨어 레지스터용 또는 프로토콜 일치용) 너비 특정 유형(예: 너비 특정 유형)을 사용합니다.
uint32_t
). - 어레이 엘리먼트0 ~ n 에 액세스 하고 싶은 어레이 리터에서는, 이것도 부호 없음(0보다 작은 인덱스에 액세스 할 필요가 없음)이 필요합니다.또한 고속 타입 중 하나를 사용합니다(예:
uint_fast16_t
모든 어레이 요소에 액세스하는 데 필요한 최소 크기에 따라 유형을 선택합니다.예를 들어, I have a new from a new first.for
최대 24개의 요소를 반복하는 루프를 사용합니다.uint_fast8_t
컴파일러(또는 stdint.h를 취득하는 방법에 따라서는 stdint.h)가 그 조작에 가장 빠른 타입을 결정하도록 합니다. - 서명해야 하는 특별한 이유가 없는 한 항상 서명되지 않은 변수를 사용하십시오.
- 부호 없는 변수와 부호 있는 변수를 함께 재생해야 하는 경우 명시적 캐스트를 사용하여 결과를 파악하십시오.(꼭 필요한 경우를 제외하고 부호 있는 변수를 사용하지 않으면 다행히 이 값은 최소화됩니다.)
그 중 하나라도 동의하지 않거나 추천할 만한 대안이 있으면 댓글로 알려주세요!그게 소프트웨어 개발자의 삶이야계속 배우지 않으면 무의미해져요
내가 언뜻 본 링크 소스코드로 미루어 볼 때, 당신은 당신이 무엇을 하고 있는지 알고 있는 것 같습니다.
"특정" 유형을 사용하면 더 많은 깁스를 할 수 있다고 말씀하셨습니다.어쨌든 그건 선택하기에 최적의 경로가 아니야.사용하다int
가능한 한 많이, 더 전문적인 유형을 요구하지 않는 것들을 위해.
의 묘미int
당신이 말하는 타입에 대해 추상화된다는 것입니다.이 기능은 구성을 시스템에 노출시킬 필요가 없는 모든 경우에 최적입니다.int
프로그램용 플랫폼을 추상화하기 위한 자체 도구입니다.또한 속도, 크기 및 정렬의 이점을 얻을 수 있습니다.
기타 모든 경우, 예를 들어 기계 사양에 의도적으로 근접하기를 원하는 경우,int
버려질 수도 있고 버려야 할 수도 있다.대표적인 예로는 데이터가 회선을 통해 전송되는 네트워크 프로토콜과 상호 운용성 기능(C와 다른 언어 사이의 브리지, C 구조에 액세스하는 커널 어셈블리 루틴)이 있습니다.하지만 가끔은 실제로 사용하고 싶을 때도 있다는 것을 잊지 마세요.int
이러한 경우에도 플랫폼에 따라서는 "표준" 또는 선호하는 단어 크기가 있기 때문에 그 속성에 의존해야 할 수 있습니다.
다음과 같은 플랫폼 유형으로uint32_t
커널은 C와 어셈블러 양쪽에서 접근할 경우 데이터 구조에서 이것들을 사용하고 싶어할 수 있습니다(필요하지는 않지만).커널은 일반적으로 C와 어셈블러 양쪽에서 액세스 할 수 있기 때문입니다.int
원래 그래야만 해
요약하자면,int
가능한 한 추상적인 타입에서 "머신" 타입(바이트/옥텟, 워드 등)으로 이행합니다.
에 대해서size_t
및 기타 "유형-유형" - 구문이 그 유형에 고유한 의미론을 따르는 한 - 예를 들어, 사용size_t
음, 모든 종류의 사이즈 값 - 나는 이의를 제기하지 않을 것이다.그러나 나는 그것이 가장 큰 종류임을 보증한다고 해서 (실제 그것이 사실인지 아닌지에 관계없이) 어떤 것에든 그것을 아낌없이 적용하지는 않을 것이다.그건 나중에 밟고 싶지 않은 수중 돌이야.코드는 가능한 한 명확하게 설명되어야 합니다.size_t
당연한 일이지만 눈살을 찌푸리게 하는 데는 그만한 이유가 있다.사용하다size_t
사이즈에 대응합니다.사용하다offset_t
오프셋을 위해.사용하다[u]intN_t
옥텟, 단어, 그런 것들을 위해서요.기타 등등.
이것은 특정 C타입 고유의 의미론, 소스 코드 및 실행 중인 프로그램에 대한 의미론에 관한 것입니다.
또한 다른 사람들이 일러스트 했듯이, 부끄러워하지 마세요.typedef
자신의 타입을 효율적으로 정의할 수 있기 때문에, 제가 개인적으로 소중히 여기는 추상화 기능입니다.좋은 프로그램 소스코드로는 1개도 노출되지 않을 수 있습니다.int
그럼에도 불구하고int
다수의 목적 정의 타입 뒤에 에일리어스 되어 있습니다.난 안 가릴 거야typedef
다른 답변들은 희망적으로 그렇게 될 겁니다
사용하고 있는 것만으로int
캐스팅의 필요성이 최소화되기 때문에 어느 곳에서나 매력적으로 보일 수 있지만, 다음과 같은 잠재적인 함정이 있습니다.
A는 생각보다 짧을 수 있습니다.대부분의 데스크톱 플랫폼에서는
int
는 일반적으로 32비트이며, C 표준에서는 최소 16비트 길이만 보증됩니다.임시 값이라도 코드에는 2-1 = 32,767보다16 큰 숫자가 필요할 수 있습니까?만약 그렇다면,int
. (사용할 수 있습니다.long
대신; along
최소 32비트가 보증됩니다).a도 항상 충분히 길지 않을 수 있습니다.특히 어레이(또는 문자열)의 길이가
char
array)는, 에 짜넣어져 있습니다.long
.사용하다size_t
(또는ptrdiff_t
부호 있는 차분이 필요한 경우)를 참조해 주세요.특히, 는 유효한 어레이 인덱스를 유지할 수 있을 정도로 충분히 크도록 정의되어 있습니다.
int
또는 심지어long
아닐지도 몰라따라서 예를 들어 어레이 상에서 반복할 경우 루프 카운터(및 그 초기값/최종값)는 일반적으로size_t
적어도 어레이가 작은 타입이 동작할 수 있을 정도로 짧다는 것을 확실히 알고 있는 경우는 제외합니다.(단, 거꾸로 반복할 때는 주의해 주세요.size_t
서명되어 있지 않기 때문에for(size_t i = n-1; i >= 0; i--)
무한 루프입니다!사용.i != SIZE_MAX
또는i != (size_t) -1
동작해야 한다, 또는 사용되어야 한다.do
/while
루프, 단, 주의할 것n == 0
!)가 서명되어 있습니다.특히 오버플로는 정의되지 않은 동작을 의미합니다.가치가 합법적으로 넘칠 위험이 있는 경우,
int
; 를 사용합니다.unsigned int
(또는unsigned long
, 또는uintNN_t
)을 클릭합니다.경우에 따라서는 고정 비트 길이만 필요할 수 있습니다.특정 길이의 정수를 필요로 하는 ABI 또는 파일 형식을 읽고 쓰는 경우, 그 길이만 사용해야 합니다(물론 이러한 상황에서는 엔디안성 등의 문제가 발생할 수 있으므로 데이터를 바이트 단위로 수동으로 패킹해야 할 수도 있습니다).
게다가 고정 길이 타입의 사용을 항상 회피하는 이유도 있습니다.int32_t
항상 입력하는 것은 어색하지만 컴파일러가 항상 32비트 정수를 사용하도록 강요하는 것은 특히 네이티브 플랫폼에서는 항상 최적의 것은 아닙니다.int
사이즈는 예를 들어 64비트일 수 있습니다.예를 들어, C99를 사용할 수 있습니다.int_fast32_t
하지만 타이핑하기가 더 어렵습니다.
따라서 안전성과 휴대성을 극대화하기 위해 개인적으로 다음과 같이 제안합니다.
공통 헤더 파일에서 일상적으로 사용할 수 있도록 다음과 같은 자체 정수 유형을 정의합니다.
#include <limits.h> typedef int i16; typedef unsigned int u16; #if UINT_MAX >= 4294967295U typedef int i32; typedef unsigned int u32; #else typedef long i32; typedef unsigned long i32; #endif
이 타입은 충분히 크기만 하면 정확한 사이즈가 중요하지 않은 타입에 사용합니다.제가 추천한 타입명은 짧고 자기 문서화되어 있기 때문에 필요에 따라 캐스트에서 사용하기 쉽고 너무 좁은 타입으로 인한 에러 위험을 최소화해야 합니다.
편리하게도
u32
그리고.u16
상기와 같이 정의된 타입은 적어도 같은 폭이어야 합니다.unsigned int
따라서 로 승격되어 정의되지 않은 오버플로 동작을 일으킬 염려 없이 안전하게 사용할 수 있습니다.사용하다
size_t
모든 배열 크기 및 인덱싱에 사용할 수 있지만 배열과 다른 정수 유형 사이에 캐스팅할 때는 주의하십시오.선택적으로 많은 밑줄을 입력하는 것을 원하지 않는 경우,typedef
좀 더 편리한 가명일 수도 있어요.특정 비트 수에서 오버플로를 가정한 계산의 경우 다음 중 하나를 사용합니다.
uintNN_t
또는 그냥 사용하세요.u16
/u32
위에서 정의한 바와 같이 명시적인 비트 마스크로&
. 를 사용하는 경우uintNN_t
예상치 못한 승진으로부터 자신을 보호해야 합니다.int
; 이를 위한 한 가지 방법은 다음과 같은 매크로를 사용하는 것입니다.#define u(x) (0U + (x))
이를 통해 다음과 같이 안전하게 작성할 수 있습니다.
uint32_t a = foo(), b = bar(); uint32_t c = u(a) * u(b); /* this is always unsigned multiply */
특정 정수 길이가 필요한 외부 ABI의 경우 다시 특정 유형을 정의합니다. 예를 들어 다음과 같습니다.
typedef int32_t fooint32; /* foo ABI needs 32-bit ints */
다시 말하지만, 이 유형 이름은 크기와 목적 모두에 대해 자체 문서화되어 있습니다.
플랫폼 및 컴파일 타임옵션에 따라 ABI가 16비트 또는 64비트 int를 실제로 필요로 하는 경우 유형 정의를 일치하도록 변경할 수 있습니다(및 유형 이름 변경).
fooint
)- 단, 그 타입에서 또는 그 타입에서 어떤 것을 캐스트 할 때는, 예기치 않게 오버플로우가 발생할 가능성이 있기 때문에, 정말로 주의가 필요합니다.코드에 특정 비트 길이가 필요한 자체 구조 또는 파일 형식이 있는 경우 외부 ABI와 동일하게 이러한 구조 또는 파일 형식을 정의하는 것도 고려해 보십시오.아니면 그냥 사용하셔도 됩니다.
uintNN_t
그 대신, 그런 식으로 하면 자기 만족감을 잃게 될 거예요.이러한 모든 유형에 대해 해당 항목을 정의하는 것을 잊지 마십시오.
_MIN
그리고._MAX
상수를 사용하여 쉽게 한계를 확인할 수 있습니다.많은 작업이 필요한 것처럼 들릴 수 있지만, 실제로는 하나의 헤더 파일에 몇 줄만 들어 있습니다.
마지막으로 정수 연산, 특히 오버플로우에는 주의해야 합니다.예를 들어, 두 개의 n비트 부호 있는 정수의 차이가 n비트 int에 맞지 않을 수 있다는 점에 유의하십시오(n-bit 부호 없는 int에는 음이 아닌 것을 알고 있으면 n비트 부호 없는 int에 들어갑니다.다만, 정의되지 않은 동작을 피하기 위해서는, 그 차이를 취하기 전에 부호 없는 타입에 입력할 필요가 있습니다).마찬가지로 두 정수의 평균을 구하려면(예: 이진수 검색)avg = (lo + hi) / 2
, 다만, 예를 들면. avg = lo + (hi + 0U - lo) / 2
합계가 넘치면 전자는 깨진다.
항상.
16비트 플랫폼에서 32767보다 큰 정수를 필요로 하는 등 특정 유형을 사용해야 하는 특별한 이유가 없는 한, 또는 네트워크 또는 파일을 통해 데이터를 교환하기 위해 적절한 바이트 순서와 부호가 필요한 경우를 제외하고(또한 리소스가 제약되지 않는 한 ASCII 또는 UTF8을 의미하는 "일반 텍스트"로 데이터를 전송하는 것을 고려하십시오.를 참조해 주세요).
내 경험에 따르면 "just use 'int'는 생활하기에 좋은 격언이며 매번 빠르고 쉽게 유지 관리할 수 있는 올바른 코드를 만들 수 있습니다.하지만 독자 분의 구체적인 상황은 다를 수 있으니, 이 조언을 잘 받아 들일 만합니다.
대부분의 경우,int
이상적이지 않습니다.가장 큰 이유는int
is signed and signed는 UB의 원인이 될 수 있으며, 부호 있는 정수는 음수일 수도 있습니다.대부분의 정수에는 필요 없습니다.부호 없는 정수를 선호합니다.둘째, 데이터 유형은 의미와 이 변수가 가질 수 있는 사용된 범위와 값을 문서화하는 매우 제한적인 방법을 반영합니다.사용하시는 경우int
이 변수가 때때로 음의 값을 유지할 것으로 예상하며, 이 값이 항상 8비트에 맞는 것은 아니지만 항상 에 맞는다는 것을 의미합니다.INT_MAX
(최소)32767
. 전제로 하지 마세요.int
32비트입니다.
항상 가능한 변수 값을 생각하고 그에 따라 유형을 선택하십시오.다음 규칙을 사용합니다.
- 음수를 처리할 수 있어야 하는 경우를 제외하고 부호 없는 정수를 사용하십시오.
- 어레이를 인덱싱하려면 처음부터
size_t
그럴 만한 이유가 있을 때 빼고요거의 사용하지 않음int
그것 때문에, a는int
크기가 너무 작을 수 있으며 충분히 큰 어레이를 테스트한 적이 없기 때문에 테스트 중에 발견되지 않는 UB 버그가 발생할 가능성이 높습니다. - 어레이 크기 및 기타 오브젝트 사이즈도 동일(우선)
size_t
. - 이미지 처리에 필요한 음의 인덱스를 사용하여 어레이를 인덱싱해야 하는 경우
ptrdiff_t
하지만 알아두세요ptrdiff_t
너무 작을 수도 있지만, 그건 드문 일입니다. - 특정 크기를 초과하지 않는 어레이가 있는 경우
uint_fastN_t
,uintN_t
, 또는uint_leastN_t
특히 8비트 마이크로컨트롤러에서는 매우 의미가 있습니다. - 가끔씩,
unsigned int
대신 사용할 수 있다uint_fast16_t
,유사하게int
위해서int_fast16_t
. - 1 바이트의 값(또는 문자는 UTF-8 및 Unicode 때문에 실제 문자가 아님)을 처리하려면 , 를 사용합니다.
int
.int
저장할 수 있다-1
오류 또는 설정되지 않은 표시기가 필요하고 문자 리터럴이 유형인 경우int
(이는 C의 경우 해당되며 C++의 경우 다른 전략을 사용할 수 있습니다).기계에서 사용하는 극히 드문 가능성이 있습니다.sizeof(int)==1 && CHAR_MIN==0
바이트를 처리할 수 없는 경우int
하지만 그런 기계는 본 적이 없다. - 다양한 목적을 위해 자신의 유형을 정의하는 것이 타당할 수 있습니다.
- 깁스가 필요한 곳에는 명시적 깁스를 사용합니다.이렇게 하면 코드가 잘 정의되어 예기치 않은 동작이 최소화됩니다.
일정 크기 이후 프로젝트에는 리스트가 필요합니다.enum
네이티브 정수 데이터 타입의 경우.매크로를 사용하여_Generic
C11로부터의 표현, 처리만 필요한 경우bool
,signed char
,short
,int
,long
,long long
및 그들의unsigned
입력된 원어민 유형에서 기본 원어민 유형을 얻습니다.이렇게 하면 파서 및 유사한 부품은 11개의 정수 유형만 처리할 수 있으며 56개의 표준 정수(제 카운트가 올바른 경우) 및 기타 비표준 유형도 처리할 수 없습니다.
언급URL : https://stackoverflow.com/questions/29197964/when-should-i-just-use-int-versus-more-sign-specific-or-size-specific-types
'programing' 카테고리의 다른 글
Vuejs에서는 기본 라우터 뷰 이외의 컴포넌트를 렌더링하는 방법 (0) | 2022.08.08 |
---|---|
Vue에서 Vue를 사용하여 mapState를 사용하여 데이터를 가져올 수 없음 (0) | 2022.08.08 |
Vue가 동적 구성 요소를 사용하여 Vuex에서 v-for의 항목을 업데이트하지 않음 (0) | 2022.08.08 |
C 또는 C++에서 비어 있지 않은 디렉토리를 프로그래밍 방식으로 제거 (0) | 2022.08.08 |
Vuex getter 반환 정의되지 않은 값 (0) | 2022.08.08 |