모든 비트를 true로 설정하기 위해 -1을 사용하는 것이 안전합니까?


132

이 패턴이 C & C ++에서 많이 사용되는 것을 보았습니다.

unsigned int flags = -1;  // all bits are true

이것이 이것을 달성하기에 좋은 휴대용 방법입니까? 또는 사용 0xffffffff또는 ~0더 나은?


1
이해가되지 않습니다. 설명해 주시겠습니까?
corazza

8
코드의 의미가 명확한 지 여부가 가장 중요한 질문이라고 생각합니다. -1항상 작동 하지만 , 주석이 명확하지 않다는 것을 보여준 후에 주석이 필요하다는 사실. 변수가 플래그 모음 인 경우 왜 정수를 할당합니까? 형식은 정수일 수 있지만 의미 상 정수는 아닙니다. 절대로 늘리거나 곱하지 않을 것입니다. 그래서 나는 0xffffffff이식성이나 정확성을 위해서가 아니라 명확성을 위해 사용할 것 입니다.
Cam Jackson

@CamJackson은 주석 이 아니며 C 코드를 작성하는 사람은 값을 나타내는 방법에 익숙 할 수 있습니다.
Miles Rout

질문은 원래 C 및 C ++로 올바르게 태그되었습니다. C ++에 2의 보수가 필요하다는 제안이 있기 때문에 언어가 다양 할 수 있습니다. 즉, -1두 언어 모두에서 이식 가능하고 이전 버전과 호환되는 솔루션으로 남아 있다는 사실은 변경되지 않지만 다른 답변의 추론에 영향을 줄 수 있습니다.
Adrian McCarthy 17

답변:


154

가장 간단한 방법이므로 표시 한대로 정확하게 수행하는 것이 좋습니다. 실제 부호 표시와 상관없이 항상-1 작동하는 초기화를 수행 하고 올바른 피연산자 유형을 가져야하기 때문에 때로는 놀라운 동작을 수행합니다. 그래야만 유형의 가치가 가장 높아집니다 .~unsigned

가능한 놀람의 예를 보려면 다음을 고려하십시오.

unsigned long a = ~0u;

모든 비트가 1 인 패턴을 반드시 저장할 필요는 없습니다 a. 그러나 먼저의 비트 1이 모두 포함 된 패턴을 unsigned int만든 다음에 할당합니다 a. unsigned long더 많은 비트가 있을 때 발생 하는 것은 모든 비트가 1이 아니라는 것입니다.

그리고이 것을 고려하십시오. 이것은 2가 아닌 보수 표현에 실패합니다 :

unsigned int a = ~0; // Should have done ~0u !

그 이유는 ~0모든 비트를 뒤집어 야하기 때문입니다 . 반전 -1하면 2의 보수 기계 (필요한 값)에서 산출 되지만 다른 표현 에서는 산출 되지 않습니다-1 . 보완 기계에서는 0을 산출합니다. 따라서 사람의 보완 시스템에서 위의 값은 a0으로 초기화 됩니다.

이해해야 할 것은 비트가 아니라 값에 관한 것입니다. 변수는 값으로 초기화됩니다 . 초기화 프로그램에서 초기화에 사용 된 변수의 비트를 수정하면 해당 비트에 따라 값이 생성됩니다. a가능한 가장 높은 값 으로 초기화 하기 위해 필요한 값은 -1또는 UINT_MAX입니다. 두 번째는 유형에 따라 달라집니다.에 a사용해야 ULONG_MAX합니다 unsigned long. 그러나 첫 번째는 유형에 의존하지 않으며 가장 높은 가치를 얻는 좋은 방법입니다.

우리는 -1 는 모든 비트가 하나 인지 (항상 그렇지 않음)에 대해 이야기 하지 않습니다. 그리고 우리는 물론 모든 비트가 1 비트 인지 여부에 대해 이야기 하지 않습니다~0 .

그러나 우리가 이야기하고있는 것은 초기화 된 flags변수 의 결과입니다 . 그리고 그것을 위해서만-1 모든 유형과 기계 작동합니다.


9
-1이 모든 것으로 변환되는 이유는 무엇입니까? 이것이 표준에 의해 보장됩니까?
jalf

9
발생하는 변환은 범위 (C TC2 초안에서 6.3.1.3)가 될 때까지 ULONG_MAX를 하나 이상 반복해서 추가한다는 것입니다. C ++에서는 형식화하는 다른 방법 (모듈로 2 ^ n)을 사용하는 것과 같습니다. 그것은 모두 수학적 관계로 귀결됩니다.
Johannes Schaub-litb

6
@litb : 캐스팅 -1은 확실히 부호없는 최대 값을 얻는 좋은 방법이지만 실제로 설명하는 것은 아닙니다. 이것이 _MAX 상수가 존재하는 이유입니다 (SIZE_MAX가 C99에 추가됨). 당연히, C ++ 버전 numeric_limits<size_t>::max()은 약간 길지만, 캐스트도 있습니다.
Christoph

11
"우리는 -1에 모든 비트가 1인지 (항상 그렇지는 않음)에 대해 이야기하지 않고있다. 그리고 ~ 0에 모든 비트가 1인지 (물론 있음)는 이야기하지 않는다." -뭐야 ??? 요점 모든 비트를 1로 설정 하는 것이라고 생각했습니다 . 이것이 플래그가 작동하는 방식입니다. 당신은 비트를 봅니다. 누가 가치에 관심이 있습니까?
mpen

14
@ 질문가가 관심을 표명하십시오. "-1을 사용하여 모든 비트를 true로 설정하는 것이 안전합니까?" 이것은 어떤 비트 -1가 표현 되는지에 대해 묻지 않으며, 어떤 비트 ~0가 무엇인지 묻지도 않습니다 . 우리는 값에 신경 쓰지 않을 수도 있지만 컴파일러는 그렇게합니다. 우리는 운영이 가치에 따라 작동한다는 사실을 무시할 수 없습니다. 의 ~0아닐 수도 -1있지만 필요한 값입니다. 내 답변과 @Dingo의 요약을 참조하십시오.
Johannes Schaub-litb

49
  • unsigned int flags = -1; 휴대용입니다.
  • unsigned int flags = ~0; 그것은 2의 보수 표현에 의존하기 때문에 이식성이 없습니다.
  • unsigned int flags = 0xffffffff; 32 비트 정수를 가정하기 때문에 이식성이 없습니다.

C 표준에서 보장하는 방식으로 모든 비트를 설정하려면 첫 번째 비트를 사용하십시오.


10
~ 0 (즉, 보수 연산자)은 2의 보수 표현에 어떻게 의존합니까?
Drew Hall

11
당신은 이것을 거꾸로 가지고 있습니다. 2의 보수 표현에 의존하는 플래그를 -1로 설정합니다. 부호 + 크기 표현에서 1을 빼면 부호 비트와 크기의 최하위 비트의 두 비트 세트 만 있습니다.
Stephen C. Steel

15
C 표준에서는 0의 int 값에 부호 비트가 있고 모든 값 비트가 0이어야합니다. 1의 보수 후에는 모든 비트가 1입니다. 모든 비트가 설정된 int의 값은 다음과 같습니다. 부호와 크기 : INT_MIN 1의 보수 : -0 2의 보수 : -1 그래서 "unsigned int flags = ~ 0;" 위의 값 중 플랫폼의 정수 표현과 일치하는 값을 지정합니다. 그러나 2의 보수 중 '-1'은 모든 플래그 비트를 하나로 설정하는 유일한 것입니다.
Dingo

9
@Stephen : 표현에 동의했습니다. 그러나 int 값이 unsigned int에 할당되면 unsigned는 int 값의 내부 표현을 채택하여 값을 얻지 못합니다 (일반적으로 작동하는 2의 보완 시스템 제외). 부호없는 int에 할당 된 모든 값은 모듈로 (UINT_MAX + 1)이므로 -1을 할당하면 내부 표현에 관계없이 작동합니다.
Dingo

20
@ Mark : 두 가지 작업을 혼동하고 있습니다. 물론 모든 비트가 설정된 값을 ~0산출합니다 int. 그러나에 an int을 할당 한다고해서 반드시 부호없는 int가 부호있는 비트 패턴과 동일한 비트 패턴을 갖는 unsigned int것은 아닙니다 . 항상 2의 보수 표현 만 있습니다. 1의 보수 또는 부호 크기 표현에서 음수 값을 결과에 다른 비트 패턴으로 할당합니다 . 이것은 C ++ 표준이 부호있는-> 부호없는 변환을 동일한 비트의 값이 아닌 모듈로 같음 값으로 정의하기 때문입니다. intunsigned int
Steve Jessop

25

솔직히 나는 모든 fff가 더 읽기 쉽다고 생각합니다. 반 패턴에 대한 의견에 관해서는, 모든 비트가 설정되고 지워지는 것을 정말로 염려한다면 어쨌든 변수의 크기에 관심이있는 상황에 있다고 주장 할 것입니다. :: uint16_t 등


그다지 신경 쓰지 않는 경우가 많지만 드문 경우입니다. 예를 들어, N 비트의 데이터 세트에서 각각 sizeof (unsigned) * CHAR_BIT 비트의 청크로 분할하여 작동하는 알고리즘.
MSalters

2
+1. 데이터 유형의 크기가 F의 수보다 큰 경우에도 (즉, 모든 비트를 true로 설정하지 않은 경우), 값을 명시 적으로 설정하기 때문에 최소한 "안전한 비트"를 알고 있습니다.
mpen

17

언급 된 문제를 피하는 방법은 간단하게 수행하는 것입니다.

unsigned int flags = 0;
flags = ~flags;

휴대가 편리합니다.


2
그러나로 선언 할 수있는 능력을 잃게 flags됩니다 const.
David Stone

1
@DavidStoneunsigned int const flags = ~0u;

@Zoidberg '-2의 보수 이외의 시스템에서는 작동하지 않습니다. 예를 들어, 부호 - 크기 시스템에서, ~01로 설정된 모든 비트를 갖는 정수이지만 그 할당 할 때 int받는 unsigned가변 flags하면에서 값 변환을 수행 -2**31(32 비트를 가정 int까지) (-2**31 % 2**32) == 2**31의 정수이고, 이는 모든 비트 만 1로 첫 세트
데이비드 스톤

이것이이 답변이 위험한 이유이기도합니다. @Zoidberg '-의 대답은 동일하지만 실제로는 그렇지 않습니다. 그러나 코드를 읽는 사람은 코드를 초기화하기 위해 두 단계를 수행 한 이유를 이해하고 코드를 한 단계로 변경하려는 유혹에 대해 생각해야합니다.
David Stone

2
아 네, u당신의 대답에 접미사를 보지 못했습니다 . 물론 작동하지만 여전히 사용하는 데이터 유형을 unsigned두 번 ( 더 크지 않은) 두 번 지정하는 데 문제가 있어 오류가 발생할 수 있습니다. 그러나 할당과 초기 변수 선언이 더 멀리 떨어져 있으면 오류가 나타날 가능성이 높습니다.
David Stone

13

플래그에 부호없는 int를 사용하는 것이 확실하지 않다는 것은 C ++의 첫 번째 장소입니다. 비트 셋 등은 어떻습니까?

std::numeric_limit<unsigned int>::max()0xffffffff부호없는 int가 32 비트 정수라고 가정 하기 때문에 더 좋습니다 .


나는 표준 때문에 이것을 좋아하지만 너무 장황하며 유형을 두 번 진술하게합니다. 0은 정수 유형일 수 있으므로 ~ 0을 사용하는 것이 더 안전합니다. (나는 그것이 너무 C의 냄새가 나는 것을 알고 있지만)
Macke

그것이 장황한 사실은 이점으로 볼 수 있습니다. 하지만 ~ 0도 좋아합니다.
Edouard A.

2
어쨌든 unsigned int 형식을 하드 코딩하기 때문에 표준 UINT_MAX 매크로를 사용하여 편견을 완화 할 수 있습니다.

2
@Macke C ++ 11에서 타입을 지정하지 않아도됩니다 auto. auto const flags = std::numeric_limit<unsigned>::max().
David Stone

11
unsigned int flags = -1;  // all bits are true

"이것이 이것을 달성하는 좋은 [,] 휴대용 방법입니까?"

가지고 다닐 수 있는? .

좋은? 이 글타래에 표시된 모든 혼란에 의해 입증되는 논쟁의 여지가 있습니다. 동료 프로그래머가 혼동없이 코드를 이해할 수있을 정도로 명확하다는 것은 좋은 코드를 측정하는 차원 중 하나 여야합니다.

또한이 방법은 컴파일러 경고 가 발생하기 쉽습니다 . 컴파일러를 방해하지 않고 경고를 없애려면 명시 적 캐스트가 필요합니다. 예를 들어

unsigned int flags = static_cast<unsigned int>(-1);

명시 적 캐스트에서는 대상 유형에주의를 기울여야합니다. 대상 유형에주의를 기울이면 다른 접근 방식의 함정을 자연스럽게 피할 수 있습니다.

내 조언은 타겟 유형에주의를 기울이고 암시 적 변환이 없는지 확인하는 것입니다. 예를 들면 다음과 같습니다.

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

모두 동료 프로그래머에게 정확하고 분명 합니다.

그리고 C ++ 11 을 사용 auto하면 다음 중 하나를 더 간단하게 만들 수 있습니다 .

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);

나는 단순히 올바른 것보다 정확하고 명백한 것으로 생각합니다.


10

표준의해 -1을 부호없는 유형으로 변환하는 것은 모든 사람을 초래합니다. 유형이 ~0U있기 때문에 일반적으로 사용이 좋지 않으며 명시 적으로와 같은 것을 쓰지 않는 한 더 큰 부호없는 유형의 모든 비트를 채우지는 않습니다 . 제정신 시스템에서는 과 동일해야 하지만, 표준은 보완 및 부호 / 크기 표현을 허용하므로 엄격히 이식성이 없다.0unsigned int~0ULL~0-1

물론 0xffffffff정확히 32 비트가 필요하다는 것을 알고 있으면 글을 쓰는 것이 좋습니다 .하지만 -1은 여러 유형에서 작동하는 매크로와 같이 유형의 크기를 모르는 경우에도 모든 컨텍스트에서 작동한다는 이점이 있습니다 또는 구현에 따라 유형의 크기가 다른 경우 당신은 유형을 알고 있다면, 다른 안전한 방법은 모든 사람이 제한 매크로입니다 얻을 UINT_MAX, ULONG_MAX,ULLONG_MAX , 등

개인적으로 나는 항상 -1을 사용합니다. 그것은 항상 작동하며 그것에 대해 생각할 필요가 없습니다.


FWIW, 내가 "모든 1 비트"를 의미한다면 ~(type)0(물론 오른쪽 type을 채우십시오 ). 0을 캐스트하면 여전히 0이되므로 명확하고 대상 유형의 모든 비트를 부정하는 것은 매우 명확하게 정의됩니다. 실제로 그 작업을 실제로 원하는 것은 아닙니다. YMMV.
Donal Fellows

6
@Donal : 당신은 단순히 틀 렸습니다. C는 부호없는 유형에 맞지 않는 값을 변환 할 때 값이 모듈로 2 ^ n 감소됨을 지정합니다. 여기서 n은 대상 유형의 비트 수입니다. 이는 부호있는 값과 더 큰 부호없는 유형 모두에 적용됩니다. 그것은 2의 보수와 관련이 없습니다.
R .. GitHub 중지 지원 얼음

2
그들은 어떻게 그것을 사소한 인 동일하게 구현; 부호있는 뺄셈 opcode 또는 부호있는 뺄셈 opcode를 사용하면 neg됩니다. 가짜 부호있는 산술 동작이있는 머신에는 별도의 부호있는 / 부호없는 산술 연산 코드가 있습니다. 물론 실제로 좋은 컴파일러는 부호있는 값의 경우에도 부호있는 opcode를 항상 무시하므로 무료로 2를 보완합니다.
R .. GitHub 중지 지원 얼음

1
@R .: 보다 좁은 부호없는 유형 인 var = ~(0*var)경우에 실패합니다 . 아마도 ? (개인적으로 나는 여전히 선호합니다 ). varintvar = ~(0U*var)-1
caf

1
이 답변은 Johannes Schaub의 답변보다 훨씬 명확합니다. 그러나 캐스트없이 부호없는 유형에 음수 리터럴 정수를 지정하면 일반적으로 컴파일러 경고가 발생합니다. 경고를 억제하려면 캐스트가 필요합니다. 어쨌든 대상 유형에주의를 기울여야합니다. 따라서 UINT_MAX 또는 ULONG_MAX를 사용하고 표준의 작은 세부 사항에 의존하지 않고 명확하게 많은 동료 프로그래머를 혼란스럽게합니다. .
Adrian McCarthy

5

만큼 당신이 가지고 #include <limits.h>포함하여 중 하나로서, 당신은 사용해야

unsigned int flags = UINT_MAX;

긴 비트를 원한다면

unsigned long flags = ULONG_MAX;

이러한 값은 부호있는 정수의 구현 방법에 관계없이 결과의 모든 값 비트가 1로 설정됩니다.


1
제안한 상수는 실제로 limits.h에 정의되어 있습니다.-stdint.h는 추가 정수 유형 (고정 크기 정수, intptr_t, ...)에 대한 제한을 포함합니다.
Christoph

5

예. 다른 답변에서 언급했듯이-1 가장 이식성이 뛰어납니다. 그러나 이것은 의미 론적이지 않으며 컴파일러 경고를 트리거합니다.

이러한 문제를 해결하려면이 간단한 도우미를 사용해보십시오.

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

용법:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;

3
C 프로그래머로서 이와 같은 코드는 밤에 나쁜 꿈을 꾼다.
jforberg

그리고 부호있는 정수가있는 ALL_BITS_TRUE ^ a곳 과 같은 상황에서 이것을 사용할 때 어떻게됩니까 a? 형식은 부호있는 정수로 유지되며 비트 패턴 (객체 표현)은 2의 보수인지 여부에 따라 다릅니다.
Peter Cordes

아니요, 모호 ALL_BITS_TRUE ^ a하기 때문에 컴파일 오류가 발생 ALL_BITS_TRUE합니다. uint32_t(ALL_BITS_TRUE) ^ a그러나 처럼 사용할 수 있습니다 . cpp.sh에서 직접 시도해 볼 수 있습니다 :) 요즘에는 사용자가 사용하려고하지 않도록에 static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");in을 추가합니다 . 답변을 업데이트하겠습니다. operatorint(ALL_BITS_TRUE)
Diamond Python

3

나는 -1 일을하지 않을 것입니다. 다소 직관적이지 않습니다 (적어도 나에게는). 서명 된 데이터를 서명되지 않은 변수에 할당하는 것은 자연스러운 사물의 순서를 위반하는 것 같습니다.

당신의 상황에서 나는 항상 0xFFFF 합니다. (물론 가변 크기에 맞는 수의 F를 사용하십시오.)

[BTW, 나는 실제 코드에서 -1 트릭을 거의 볼 수 없다.]

당신이 정말 vairable의 개별 비트 걱정하는 경우 또한, 그것은 고정 폭을 사용하여 시작하는 좋은 방법이 될 것입니다 uint8_t, uint16_t, uint32_t유형.


2

인텔의 IA-32 프로세서에서는 0xFFFFFFFF를 64 비트 레지스터에 쓰고 예상 결과를 얻는 것이 좋습니다. IA32e (IA32의 64 비트 확장)는 32 비트 즉시 지원 만하기 때문입니다. 64 비트 명령어에서 32 비트 즉시 부호부호 확장됩니다. 64 비트로 됩니다.

다음은 불법입니다 :

mov rax, 0ffffffffffffffffh

다음은 RAX에 64 1을 넣습니다.

mov rax, 0ffffffffh

완전성을 위해 다음은 RAX (일명 EAX)의 하단에 32 1을 넣습니다.

mov eax, 0ffffffffh

실제로 64 비트 변수에 0xffffffff를 쓰려고 할 때 프로그램이 실패했으며 대신 0xffffffffffffffff를 얻었습니다. C에서 이것은 다음과 같습니다.

uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);

결과는 다음과 같습니다.

x is 0xffffffffffffffff

나는 이것을 0xFFFFFFFF가 32 비트로 가정한다고 말한 모든 대답에 대한 의견으로 이것을 게시하려고 생각했지만 많은 사람들이 대답했다. 나는 그것을 별도의 답변으로 추가 할 것이라고 생각했다.


1
축하합니다. 컴파일러 버그를 발견했습니다!
tc.

이것은 버그로 문서화 되었습니까?
Nathan Fellman

1
UINT64_C(0xffffffff)과 같은 것으로 확장 한다고 가정하면 0xffffffffuLL분명히 컴파일러 버그입니다. C 표준은 에 대해 주로 설명 하고, 값 0xffffffff은 4294967295 (36893488147419103231 아님)이며 부호있는 정수 유형으로 변환되지 않습니다.
tc.

2

문제에 대한 명확한 설명은 litb의 답변을 참조하십시오.

나는 매우 엄격하게 말해서 두 경우 모두에 대한 보장이 없다는 것에 동의하지 않습니다. 나는 모든 비트 세트로서 '비트 수만큼 2의 1보다 작은'의 부호없는 값을 나타내지 않는 아키텍처를 모른다. 그러나 표준이 실제로 말하는 것 (3.9.1 / 7 plus) 주 44) :

정수형의 표현은 순수한 이진법을 사용하여 값을 정의해야한다. [참고 44 :] 이진수 0과 1을 사용하는 정수의 위치 표현은 연속 비트로 표시되는 값이 가산적이고 1로 시작하며 연속 정수로 2를 곱한 값입니다. 가장 높은 위치.

그것은 비트 중 하나가 전혀 될 가능성을 남겨 둡니다.


일반적으로 패딩 비트의 값을 확신 할 수 없습니다. 원하는 경우 트랩 표현을 생성 할 수 있고 신호를 발생시킬 수 있으므로 위험에 처할 수 있습니다. 그러나 std에는 부호없는 char에 패딩 비트가 없어야하며 C ++ 표준의 4.7 / 2에서는 정수를 부호없는 유형으로 변환하면 결과 부호없는 변수의 값은 소스 정수 값에 맞는 가장 작은 값입니다. (부호없는 2 ^ n, n == 부호없는 유형의 비트 수). 그런 다음 (-1) == ((2 ^ n) -1) (mod 2 ^ n). 2 ^ n-1은 순수한 이진수 시스템에서 모든 비트를 설정했습니다.
요하네스 샤 우브-litb

우리가하면 정말 부호없는 형식의 객체 표현의 모든 비트 하나를 갖고 싶어, 우리는 memset 함수가 필요합니다. 그러나 우리는 함정 표현을 생성 할 수 있습니다 : (어쨌든 구현에는 부호없는 정수를 조금 버릴 이유가 없으므로 값을 저장하는 데 사용할 것입니다. 그러나 당신은 아주 좋은 지적을 얻었습니다-멈추지 않습니다. 바보 같은 말도 안되는 비트가 몇 가지있는 해석, 나는 생각한다 (char / signed char / unsigned char, 그것들은 없어야 함) +1 물론 :)
Johannes Schaub-litb

결국, 나는 표준이 4.7 / 2에서 어떤 표현을 나타내는 지 더 명확하게 생각할 수 있다고 생각합니다. 그것이 객체 표현을 언급한다면, 더 이상 비트를 채울 수있는 곳이 없습니다 (나는 사람들이 내가 잘못 보지 않는 것과 같은 논쟁을하는 것을 보았습니다). 그러나 나는 그것이 가치 표현에 대해 이야기한다고 생각합니다 (4.7 / 2의 모든 것이 어쨌든 가치에 관한 것이기 때문에 패딩 비트가 가치 비트 옆에 중첩 될 수 있습니다.
Johannes Schaub-litb

1
표준은 '2의 보수, 1의 보수 및 부호가있는 크기'표상을 명쾌하게 가지고있는 것처럼 보이지만 아무것도 배제하고 싶지 않습니다. 트 랩핑 표현에 대한 흥미로운 점. 내가 말할 수있는 한, 인용 한 비트는 표준에 관한 한 '순수 이진 계산 시스템'의 정의입니다. 끝의 '제외'비트는 실제로 캐스팅 -1이 보장되는지 여부에 대한 유일한 의심입니다. 작업.
James Hopkin

2

(가)하더라도 0xFFFF(또는 0xFFFFFFFF, 등)를 쉽게 읽을 수있다, 그렇지 않으면 휴대용 될 코드 이식성을 끊을 수있다. 예를 들어, 데이터 구조에서 특정 비트 세트 (호출자가 지정한 정확한 비트)가있는 항목 수를 계산하는 라이브러리 루틴을 고려하십시오. 루틴은 비트가 무엇을 나타내는 지에 대해 완전히 독립적 일 수 있지만 여전히 "모든 비트 세트"상수를 가져야합니다. 이러한 경우, -1은 모든 비트 크기에서 작동하므로 16 진 상수보다 훨씬 낫습니다.

다른 가능성 typedef은 비트 마스크에 값이 사용 되면 ~ (bitMaskType) 0; 비트 마스크는 16 비트 유형으로 발생하는 경우, 그 표현은 16 비트 ( 'INT'는 달리 32 비트 될 경우에도) 설정되어 있지만 16 비트가 필요한 모든 것을 할 것이기 때문에, 일이 잘되어야됩니다 제공 한 것으로 실제로 타입 캐스트에서 적절한 타입을 사용합니다.

longvar &= ~[hex_constant]또한 16 진 상수가에 비해 너무 크지 만에 적합 하면 양식의 표현에 불쾌감 int을 줄 수 unsigned int있습니다. a int가 16 비트이면 longvar &= ~0x4000;또는 longvar &= ~0x10000; 한 비트의 삭제됩니다 longvar만, longvar &= ~0x8000;그 위의 비트 (15)와 모든 비트를 지 웁니다. 적합한 값 int은 보수 연산자를 유형에 적용 int하지만 결과는 부호로 확장되어 long상위 비트를 설정합니다. 너무 큰 값은 unsigned int유형에 보수 연산자가 적용됩니다 long. 그러나이 크기 사이의 값은 보수 연산자를 type에 적용한 unsigned int다음 long부호 확장없이 type으로 변환됩니다 .


1

실용적으로 : 예

이론적으로 : 아니다.

-1 = 0xFFFFFFFF (또는 int가 플랫폼에있는 크기에 관계없이)는 2의 보수 산술에만 적용됩니다. 실제로는 작동하지만 2의 보수 표현이 아닌 실제 부호 비트가있는 레거시 시스템 (IBM 메인 프레임 등)이 있습니다. 제안 된 ~ 0 솔루션은 모든 곳에서 작동해야합니다.


6
나도 그렇게 말했다. 그러나 값 표현에 관계없이 -1 부호가 변환 규칙에서 항상 부호없는 max_value로 변환되기 때문에 내가 틀렸다는 것을 깨달았습니다. 적어도 C ++에서는 C 표준이 없습니다.
Steve Jessop

6
모호성이 있습니다. -1은 0xFFFFFFFF가 아닙니다. 그러나 부호없는 int (32 비트)로 변환하면 -1은 0xFFFFFFFF입니다. 그것이 제가이 토론을 너무 어렵게 만드는 이유입니다. 많은 사람들은 비트 열에 대해 이야기 할 때 매우 다른 것을 염두에두고 있습니다.
Johannes Schaub-litb

1

다른 사람들이 언급했듯이 -1은 모든 비트를 1로 설정하여 부호없는 유형으로 변환하는 정수를 만드는 올바른 방법입니다. 그러나 C ++에서 가장 중요한 것은 올바른 유형을 사용하는 것입니다. 따라서 귀하의 문제에 대한 정답 (귀하의 질문에 대한 답변 포함)은 다음과 같습니다.

std::bitset<32> const flags(-1);

여기에는 항상 필요한 정확한 비트 수가 포함됩니다. std::bitset다른 답변에서 언급 한 것과 동일한 이유로 모든 비트가 1로 설정된 a 를 구성 합니다.


0

-1에 항상 사용 가능한 모든 비트가 설정되어 있기 때문에 확실히 안전하지만 ~ 0이 더 좋습니다. -1은별로 의미가 없습니다 unsigned int. 0xFF... 유형의 너비에 따라 다르므로 좋지 않습니다.


4
"0xFF ...는 타입의 너비에 따라 다르기 때문에 좋지 않습니다." 프로그램에서 각 플래그 / 비트의 의미를 명확하게 정의해야합니다. 따라서 플래그를 저장하기 위해 가장 낮은 32 비트를 사용한다고 정의한 경우 int의 실제 크기가 32인지 64인지에 관계없이 32 비트를 사용하도록 제한해야합니다.
Juan Pablo Califano

0

내가 말하다:

int x;
memset(&x, 0xFF, sizeof(int));

이것은 항상 당신에게 원하는 결과를 줄 것입니다.


4
9 비트 문자가있는 시스템에는 없습니다!
tc.

0

부호없는 유형에 대해 모든 비트를 1에 할당하는 것은 주어진 유형에 대해 가능한 최대 값을 취하고
질문의 범위를 모든 부호없는 정수 유형 으로 확장하는 것과 같습니다.

-1을 할당하면 C 및 C ++ 모두 에 대해 부호없는 정수 유형 (부호없는 int, uint8_t, uint16_t 등)에 적용됩니다.

대안으로 C ++의 경우 다음 중 하나를 수행 할 수 있습니다.

  1. 포함 <limits>및 사용std::numeric_limits< your_type >::max()
  2. 쓰기 사용자 정의 템플릿 기능을 (대상 유형은 정말 부호없는 형식 인 경우도 즉 약간의 전성 검사를 허용 것)

할당에는 -1항상 설명 주석이 필요하므로 목적이 더 명확해질 수 있습니다 .


0

의미를 좀 더 명확하게 만들고 유형을 반복하지 않는 방법 :

const auto flags = static_cast<unsigned int>(-1);

-6

예, 표시된 표현은 우리가 다른 방식으로하는 것처럼 매우 정확합니다 .u는 연산자가 모든 비트를 반전시켜야하지만이 경우 기계의 정수 크기를 고려하면 논리는 매우 간단합니다.

예를 들어 대부분의 컴퓨터에서 정수는 2 바이트 = 16 비트이며, 보유 할 수있는 최대 값은 2 ^ 16-1 = 65535 2 ^ 16 = 65536입니다.

0 % 65536 = 0 -1 % 65536 = 65535 1111에 해당하고 모든 비트는 1로 설정됩니다 (잔류 물 클래스 mod 65536을 고려하면). 똑바로.

나는 추측한다

아니요.이 개념을 고려하면 서명되지 않은 정수에 대해 완벽하게 식사하고 실제로 작동합니다.

다음 프로그램 조각을 확인하십시오.

int main () {

unsigned int a=2;

cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));

unsigned int b=-1;

cout<<"\n"<<b;

getchar();

return 0;

}

b = 4294967295에 대한 답변 whcih는 4 바이트 정수에서 -1 % 2 ^ 32입니다.

따라서 부호없는 정수에 완벽하게 유효합니다.

불일치 plzz 보고서의 경우


9
두 가지 의견 : 첫째,“가장 많은”기계의 정수 크기에 대해 틀렸다. 둘째, ur txt iz는 매우 어렵습니다. Plz us 일반 영어 .
Konrad Rudolph
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.