서명되지 않은 정수에 관한 모범 사례는 무엇입니까?


43

나는 사방에 부호없는 정수를 사용하며, 내가 해야하는지 확실하지 않습니다. 이것은 데이터베이스 기본 키 ID 열에서 카운터 등이 될 수 있습니다. 숫자가 음수가 아니어야 할 경우 항상 부호없는 int를 사용합니다.

그러나 다른 사람의 코드에서 아무도이 작업을 수행하지 않는 것으로 나타났습니다. 내가 간과해야 할 중요한 것이 있습니까?

편집 :이 질문 이후 C에서도 C ++에서와 같이 예외를 throw하는 대신 오류에 대해 음수 값을 반환하는 것이 일반적이라는 것을 알았습니다.


26
조심하십시오 for(unsigned int n = 10; n >= 0; n --)(무한 루프 반복)
Chris Burt-Brown

3
C 및 C ++에서 부호없는 정수는 오버플로 동작을 정확하게 정의했습니다 (모듈로 2 ^ n). 서명 된 정수는 그렇지 않습니다. 옵티마이 저는 정의되지 않은 오버플로 동작을 점점 더 많이 활용하여 경우에 따라 놀라운 결과를 초래합니다.
Steve314

2
좋은 질문! 나도 한 번은 범위를 제한하는 uints를 사용하고 싶었지만 위험 / 불편이 어떤 이점 / 편의보다 중요하다는 것을 알았습니다. 당신이 말했듯이 대부분의 라이브러리는 uint가 할 수있는 정기적 인 정수를 허용합니다. 이로 인해 작업하기가 어려워지고 질문도 제기됩니다. 그만한 가치가 있습니까? 실제로 (멍청한 방식으로 일을하지 않는다고 가정 할 때) 긍정적 인 것이 예상되는 곳에서는 거의 -218의 값이 나오지 않습니다. -218은 어딘가에서 왔을 것입니다. 원점을 추적 할 수 있습니다. 거의 발생하지 않습니다. 어설 션, 예외, 코드 계약을 활용하여 도움을 받으십시오.
Job

@William Ting : C / C ++에만 해당되는 경우 질문에 적절한 태그를 추가해야합니다.
CesarGon

2
@Chris : 실제로 무한 루프 문제는 얼마나 중요합니까? 내 말은, 그것이 출시되면 코드는 테스트되지 않은 것입니다. 이 오류를 처음으로 만들 때 디버깅하는 데 몇 시간이 필요한 경우에도 두 번째로 코드 반복이 중지되지 않을 때 가장 먼저 찾아야 할 사항을 알아야합니다.
보안

답변:


28

내가 간과해야 할 중요한 것이 있습니까?

계산에 다른 크기뿐만 아니라 부호있는 유형과 부호없는 유형이 모두 포함 된 경우 유형 승격 규칙이 복잡하고 예기치 않은 동작발생할 수 있습니다 .

이것이 Java가 unsigned int 유형을 생략 한 주된 이유라고 생각합니다.


3
또 다른 해결책은 적절하게 숫자를 수동으로 전송하도록 요구하는 것입니다. 이것은 Go 가하는 것처럼 보이는 것입니다 (작지만 약간만 가지고 놀았습니다) .Java의 접근법보다 더 좋아합니다.
Tikhon Jelvis

2
이것이 Java가 64 비트 부호없는 유형을 포함하지 않는 좋은 이유였으며, 32 비트 부호없는 유형을 포함하지 않는 적절한 이유 일 것입니다. 이러한 작업은 단순히 64 비트 부호있는 결과를 생성해야합니다]. 그러나 부호가없는 유형 int은 계산이 촉진되기 때문에 그다지 어렵지 않습니다 int. 부호없는 바이트 유형이 없다고 말할 수있는 것은 없습니다.
supercat

17

나는 Michael 이 타당한 점을 가지고 있다고 생각 하지만, IMO가 모두 int를 항상 (특히에서 for (int i = 0; i < max, i++) 사용하는 이유 는 우리가 그렇게 배웠기 때문입니다. ' 프로그래밍을 배우는 방법 '책의 모든 단일 예제 intfor루프 에서 사용될 때, 그 실천에 의문을 제기하는 사람은 거의 없습니다.

다른 이유는 그것 int보다 25 % 짧고 uint, 우리 모두 게으르다 ... ;-)


2
교육 문제에 동의합니다. 대부분의 사람들은 자신이 읽은 내용에 의문을 제기하지 않는 것 같습니다 . 책에 있다면 잘못 될 수 없습니다.
Matthieu M.

1
++루프 인덱스가 반복자 또는 다른 기본이 아닌 유형 (또는 컴파일러가 실제로 밀도가 높은 경우) 인 경우 특정 동작이 거의 필요하지 않고 사본에 대한 무의미한 이탈을 초래할 수 있음에도 불구하고 모든 사람이 증분 할 때 postfix를 사용하는 이유 일 것 입니다. .
underscore_d

"for (uint i = 10; i> = 0; --i)"와 같은 것을하지 마십시오. 루프 변수에 정수만 사용하면 이러한 가능성을 피할 수 있습니다.
David Thornley


8

부호있는 유형과 부호없는 유형을 혼합하면 고통의 세계에 빠질 수 있습니다. 음수를 포함하는 유효한 범위를 가지거나 오류를 나타내는 값이 필요하고 -1이 가장 자연 스럽기 때문에 모든 부호없는 유형을 사용할 수는 없습니다. 결과적으로 많은 프로그래머가 부호있는 정수 유형을 모두 사용합니다.


1
동일한 변수에 유효한 값을 오류 표시와 혼합하지 않고 별도의 변수를 사용하는 것이 좋습니다. 물론 C 표준 라이브러리는 여기서 좋은 예를 제시하지 않습니다.
보안

7

나에게 유형은 의사 소통에 관한 것이다. 부호없는 int를 명시 적으로 사용하면 부호있는 값이 유효한 값이 아니라고 알려줍니다. 변수 이름 외에 코드를 읽을 때 정보를 추가 할 수 있습니다. 이상적으로 나는 익명이 아닌 유형으로 더 많은 것을 알 수 있지만 어디에서나 정수를 사용했을 때보 다 더 많은 정보를 제공합니다.

불행히도 모든 사람이 자신의 코드가 통신하는 것에 대해 매우 의식하지는 않으며, 값이 적어도 부호가 없더라도 모든 곳에서 int를 보는 이유 일 것입니다.


4
그러나 한 달 동안의 값을 1에서 12까지로 제한하고 싶을 수도 있습니다. 다른 유형을 사용합니까? 한 달은 어때요? 일부 언어는 실제로 그런 값을 제한 할 수 있습니다. .Net / C #과 같은 다른 코드 계약을 제공합니다. 음수가 아닌 정수가 자주 발생하지만이 유형을 지원하는 대부분의 언어는 추가 제한을 지원하지 않습니다. 따라서 uint와 오류 검사를 혼합하여 사용해야합니까, 아니면 오류 검사를 통해 모든 것을 수행해야합니까? 대부분의 라이브러리는 하나를 사용하는 것이 적합한 곳에서 uint를 요구하지 않으므로 하나를 사용하고 캐스팅하는 것이 불편할 수 있습니다.
직업

@Job 나는 몇 달 동안 어떤 종류의 컴파일러 / 통역사 강제 제한을 사용해야한다고 말하고 싶습니다. 설정을위한 상용구를 제공 할 수도 있지만 앞으로는 오류를 방지하고 예상 한 내용을보다 명확하게 전달하는 제한이 적용됩니다. 구현하는 동안 불편 함보다 오류 방지 및 의사 소통 완화가 훨씬 중요합니다.
daramarak

1
"한 달의 값을 1에서 12로만 제한하고 싶을 수 있습니다."달 과 같은 유한 한 값 집합이있는 경우 원시 정수가 아닌 열거 유형을 사용해야합니다.
Josh Caswell

6

unsigned int배열 인덱스, 주로 0부터 시작하는 모든 카운터에 대해 C ++에서 사용 합니다. 명시 적으로 "이 변수는 음수 일 수 없습니다"라고 말하는 것이 좋습니다.


14
아마 C ++에서 size_t를 사용해야 할 것입니다
JohnB

2
나는 단지 귀찮게 할 수 없다는 것을 안다.
quant_dev

3

실제로 부호있는 정수의 한계에 도달하거나 초과 할 수있는 정수를 처리 할 때이 문제를 고려해야합니다. 32 비트 정수의 양의 최대 값이 2,147,483,647이므로 a) 절대 음수가 아니며 b) 2,147,483,648에 도달 할 수 있음을 알고 있으면 부호없는 int를 사용해야합니다. 데이터베이스 키와 카운터를 포함하여 대부분의 경우 이러한 종류의 숫자에 접근하지 않으므로 부호 비트가 숫자 값으로 사용되는지 부호를 나타내는 지 걱정할 필요가 없습니다.

나는 말할 것입니다 : unsigned int가 필요하다는 것을 알지 못하면 int를 사용하십시오.


2
최대 값에 도달 할 수있는 값으로 작업 할 때는 부호에 관계없이 정수 오버플로에 대한 연산을 확인해야합니다. 대부분의 작업에는 정의되지 않은 구현 및 정의 된 동작이없는 잘 정의 된 결과가 있으므로 이러한 검사는 일반적으로 서명되지 않은 유형에 더 쉽습니다.
보안

3

단순성과 신뢰성의 균형입니다. 컴파일 타임에 잡을 수있는 버그가 많을수록 소프트웨어의 안정성이 높아집니다. 다른 사람들과 조직은 그 스펙트럼을 따라 다른 지점에 있습니다.

Ada에서 신뢰성이 높은 프로그래밍을 수행하는 경우 피트 거리 대 미터 거리와 같은 변수에 대해 다른 유형을 사용하고 실수로 다른 것을 할당하면 컴파일러에서 플래그를 지정합니다. 그것은 유도 미사일을 프로그래밍하는 데는 완벽하지만 웹 양식의 유효성을 검사하는 경우 과도하게 사용됩니다. 요구 사항에 맞는 한 어떤 방식 으로든 문제가있는 것은 아닙니다.


2

나는 Joel Etherton의 추론에 동의하는 경향이 있지만 반대 결론에 도달합니다. 내가 보는 방식으로, 숫자가 부호있는 유형의 한계에 도달 하지 않을 것임을 알고 있지만 음수가 발생하지 않는다는 것을 알고 있다면 부호있는 유형의 변형을 사용해야 할 이유가 거의 없습니다.

같은 이유로 일부 선택 인스턴스 에서 SQL Server 테이블에서 (32 BIGINT비트 정수) 대신 INTEGER(32 비트 정수)를 사용했습니다. 합리적인 시간 내에 데이터가 32 비트 제한에 도달 할 확률은 적지 만, 이러한 상황이 발생하면 결과가 상당히 치명적일 수 있습니다. 언어간에 유형을 올바르게 매핑해야합니다.

즉, 데이터베이스 기본 키 값과 같이 서명되거나 서명되지 않은 것과 같은 일부는 실제로 중요하지 않습니다. 깨진 데이터 나 그 라인을 따라 무언가를 수동으로 복구하지 않는 한 값을 직접 처리하지 않기 때문입니다. 그것은 식별자 일뿐입니다. 이러한 경우 일관성있는 서명의 정확한 선택보다 일관성이 더 중요합니다. 그렇지 않으면 서명 된 외래 키 열과 서명되지 않은 외래 키 열이 생길 수 있습니다.


SAP 시스템에서 추출한 데이터로 작업하는 경우 CustomerNumber, ArticleNumber 등의 ID 필드에 BIGINT를 사용하는 것이 좋습니다. 아무도 영숫자 문자열을 ID로 사용하지 않는 한 ... sigh
Treb

1

공간 제약이있는 데이터 저장 및 데이터 교환 컨텍스트 외부에서는 일반적으로 서명 된 형식을 사용해야합니다. 32 비트 부호있는 정수가 너무 작지만 현재 32 비트 부호없는 값으로 충분할 경우 대부분 32 비트 부호없는 값이 충분히 크지 않을 때까지 그리 오래 걸리지 않습니다.

부호없는 유형을 사용해야하는 1 차 시간은 여러 값을 더 큰 값으로 어셈블하거나 (예 : 4 바이트를 32 비트 숫자로 변환) 더 큰 값을 더 작은 값으로 분해하는 경우입니다 (예 : 32 비트 숫자를 4 바이트로 저장) ) 또는 정기적으로 "롤오버"할 것으로 예상되는 수량이 있고이를 처리해야하는 경우 (주거용 유틸리티 미터를 생각하십시오. 대부분의 숫자는 판독 값 사이에 롤오버되지 않도록 충분한 숫자를 갖습니다. 1 년에 3 번 읽었지만 미터의 유효 수명 내에 롤오버되지 않을 정도로 충분하지 않은 경우) 부호없는 유형은 종종 의미가 필요한 경우에만 사용해야하는 충분한 '이상성'을 가지고 있습니다.


1
"[...] 일반적으로 서명 된 형식을 사용하는 것이 좋습니다." 흠, 당신은 서명 된 유형의 장점을 언급하는 것을 잊었고 서명되지 않은 유형을 사용할 때만 목록을 제공했습니다. "이상 함" ? 대부분의 서명되지 않은 작업에는 잘 정의 된 동작 및 결과가 있지만 서명 된 유형 (오버플로, 비트 이동 등)을 사용할 때 정의되지 않은 구현 정의 동작을 입력합니다. 여기에 "이상 함"에 대한 이상한 정의가 있습니다.
고정

1
@Secure : 내가 참조하는 "이상성"은 비교 연산자의 시맨틱과 관련이 있습니다. 특히 부호있는 유형과 부호없는 유형이 혼합 된 작업에서 특히 그렇습니다. 오버플로하기에 충분히 큰 값을 사용하는 경우 부호있는 유형의 동작이 정의되지 않은 것이 맞지만, 비교적 작은 숫자를 처리 할 때도 부호없는 유형의 동작은 놀랍습니다. 예를 들어 (-3) + (1u)는 -1보다 큽니다. 또한 숫자에 적용되는 일반적인 수학적 연관 관계는 부호없는 문자에는 적용되지 않습니다. 예를 들어, (ab)> c는 (ac)> b를 의미하지 않습니다.
supercat

1
@Secure : "큰"부호가있는 숫자와 같은 연관 동작에 항상 의존 할 수는 없지만, 부호있는 정수의 도메인에 비해 "작은"숫자를 처리 할 때 동작이 예상대로 작동합니다. 대조적으로, 상기 언급 된 비 연관은 부호없는 값 "2 3 1"에 문제가있다. 또한 서명 된 동작이 범위를 벗어난 상태에서 사용될 때 정의되지 않은 동작이 있다는 사실은 기본 단어 크기보다 작은 값을 사용할 때 일부 플랫폼에서 코드 생성을 향상시킬 수 있습니다.
supercat

1
이러한 의견이 어떤 이유도없이 추천과 "이름 부르기"대신에 당신의 대답에 들어간 적이 있다면, 나는 언급하지 않았을 것입니다. ;) 여기서 "이상 함"에 여전히 동의하지는 않지만 단순히 유형의 정의입니다. 주어진 작업에 적합한 도구를 사용하고 도구를 알고 있어야합니다. +/- 관계가 필요할 때 부호없는 유형은 잘못된 도구입니다. size_t서명이없고 ptrdiff_t서명 된 이유 가 있습니다.
보안

1
@Secure : 원하는 비트 시퀀스를 나타내는 것이면 부호없는 유형이 좋습니다. 나는 우리가 거기에 동의한다고 생각합니다. 그리고 일부 소형 마이크로에서는 부호없는 유형이 수치 적으로 더 효율적일 수 있습니다. 델타가 숫자의 수량을 나타내지 만 실제 값이 그렇지 않은 경우 (예 : TCP 시퀀스 번호)에도 유용합니다. 반면 부호없는 값을 뺄 때마다 숫자가 작더라도 코너 케이스에 대해 걱정해야합니다. 부호있는 값을 가진 수학은 숫자가 클 때만 코너 케이스를 나타냅니다.
supercat

1

서명되지 않은 정수를 사용하여 코드와 의도를보다 명확하게 만듭니다. 부호있는 유형과 부호없는 유형으로 산술을 수행 할 때 예기치 않은 암시 적 변환을 방지하기 위해 서명하지 않은 변수에 부호없는 짧은 (일반적으로 2 바이트)을 사용하는 것입니다. 이것은 몇 가지 이유로 효과적입니다.

  • 부호없는 짧은 변수 및 리터럴 (int 유형) 또는 int 유형의 변수로 산술을 수행하면 int는 항상 short보다 높은 순위를 가지므로 표현식을 평가하기 전에 부호없는 변수가 항상 int로 승격됩니다 . 이렇게하면 표현식의 결과가 물론 부호있는 정수에 적합하다고 가정 할 때 부호있는 유형과 부호없는 유형으로 산술을 수행하는 예기치 않은 동작이 발생하지 않습니다.
  • 대부분의 경우 사용중인 부호없는 변수는 부호없는 2 바이트 short (65,535)의 최대 값을 초과하지 않습니다.

일반적으로 서명되지 않은 변수의 유형은 서명 된 유형으로 승격시키기 위해 서명 된 변수의 유형보다 순위가 낮아야합니다. 그러면 예기치 않은 오버플로 동작이 발생하지 않습니다. 분명히 이것을 항상 보장 할 수는 없지만 대부분 이것을 보장하는 것이 가능합니다.

예를 들어 최근에 다음과 같은 for 루프가 있습니다.

const unsigned short cuint = 5;
for(unsigned short i=0; i<10; ++i)
{
    if((i-2)%cuint == 0)
    {
       //Do something
    }
}

리터럴 '2'는 int 유형입니다. 내가 부호없는 short 대신 부호없는 int 인 경우 하위 표현식 (i-2)에서 2는 부호없는 int로 승격됩니다 (부호없는 int가 부호있는 int보다 우선 순위가 높기 때문에). i = 0이면 하위 표현식은 오버플로로 인해 (0u-2u) = 일부 대규모 값과 같습니다. i = 1과 동일한 아이디어입니다. 그러나 i는 부호가없는 short이므로 int로 서명 된 리터럴 '2'와 동일한 유형으로 승격되며 모든 것이 올바르게 작동합니다.

안전성 향상을 위해 : 드물게 구현하는 아키텍처가 int를 2 바이트로 만드는 경우 부호없는 짧은 변수가 맞지 않는 경우 산술 표현식의 두 피연산자가 모두 부호없는 int로 승격 될 수 있습니다. 부호가있는 2 바이트 int로 들어가고, 후자는 최대 값이 32,767 <65,535입니다. (참조 https://stackoverflow.com/questions/17832815/c-implicit-conversion-signed-unsigned을 자세한 내용). 이를 막기 위해 다음과 같이 프로그램에 static_assert를 추가하면됩니다.

static_assert(sizeof(int) == 4, "int must be 4 bytes");

int가 2 바이트 인 아키텍처에서는 컴파일되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.