서명되지 않은 긴' 변수를 인덱싱하고 결과를 출력합니다.
어제 누군가 나에게 다음 코드를 보여줬습니다.
#include <stdio.h>
int main(void)
{
unsigned long foo = 506097522914230528;
for (int i = 0; i < sizeof(unsigned long); ++i)
printf("%u ", *(((unsigned char *) &foo) + i));
putchar('\n');
return 0;
}
결과는 다음과 같습니다.
0 1 2 3 4 5 6 7
에 스럽습니다에 혼란스럽습니다.for
프 요.로는,로는,&foo
다에게 unsigned char *
됩니다에 의해 됩니다.i
.생각합니다*(((unsigned char *) &foo) + i)
입니다를 더 하게 쓰는 입니다.((unsigned char *) &foo)[i]
..foo
, unsigned long
색인화 중입니다.그렇다면 왜?나머지 루프는 배열의 모든 요소를 인쇄하는 데 전형적인 것처럼 보이기 때문에 모든 것이 사실임을 나타내는 것 같습니다.o.unsigned char *
더 혼란스럽습니다.에 대해 .char *
다 이 되지 않는 에 제 되었습니다.int
.char
,itoa()
.506097522914230528
합니다를 특별히 합니다.0 1 2 3 4 5 6 7
은 그들 것처럼 큰 은 더 것처럼 .한 8 , 0 .
서문으로서, 이 프로그램은 구현 정의된 동작을 보여주기 때문에 반드시 질문에서와 동일하게 실행되지는 않을 것입니다.이 외에도 프로그램을 약간 조정하면 정의되지 않은 동작이 발생할 수 있습니다.이것에 대한 자세한 내용은 마지막에.
첫줄.main
다합니다.unsigned long foo
~하듯이506097522914230528
. , 16 .0x0706050403020100
.
됩니다 됩니다.0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
. 지금쯤이면 출력과의 관계를 알 수 있을 겁니다.이것이 출력으로 어떻게 변환되는지 여전히 혼란스럽다면 for loop을 살펴보세요.
for (int i = 0; i < sizeof(unsigned long); ++i)
printf("%u ", *(((unsigned char *) &foo) + i));
long
길이는 8바이트이며, 이 루프는 8번 실행됩니다(remember를 들어, 16진수 2개면 바이트의 가능한 모든 값을 표시할 수 있으며, 16진수에 16자리가 있으므로 결과는 8이므로 for 루프는 8번 실행됩니다).이제 진짜 헷갈리는 부분은 두 번째 줄입니다.이런 식으로 생각해 보세요: 앞서 언급했듯이, 두 개의 16진수는 한 바이트의 가능한 모든 값을 보여줄 수 있습니다. 그렇죠?그래서 만약 우리가 이 숫자의 마지막 두 자리를 분리할 수 있다면, 우리는 7바이트의 값을 얻게 될 것입니다!자, 이제, 가정해 보세요.long
는 사실 다음과 같은 배열입니다.
{00, 01, 02, 03, 04, 05, 06, 07}
우리는 주소를 알 수 있습니다.foo
와 함께&foo
, 그것을 …에게 던지다unsigned char *
두 을 구합니다.foo[i]
한다면foo
는 8바이트의 배열입니다.제 했듯이,다만큼 덜 .((unsigned char *) &foo)[i]
.
약간의 경고:이 프로그램은 구현이 정의된 동작을 보여줍니다.이는 이 프로그램이 반드시 C의 모든 구현에 대해 동일한 방식으로 작동하는 것은 아님을 의미합니다.일부 구현에서 32비트 길이가 길 뿐만 아니라 다음과 같이 선언할 때unsigned long
, /의0x0706050403020100
(AKAendianness) 또한 구현이 정의되어 있습니다.구현 정의 동작을 먼저 지적한 @philipxy에게 공을 돌립니다.이 유형의 펀닝은 @Russlan이 지적한 또 다른 문제를 야기합니다. 즉, 만약.long
되었습니다가 아닌 됩니다.char *
/unsigned char *
, C의 엄격한 앨리어싱 규칙이 적용되고 정의되지 않은 행동을 하게 됩니다(링크의 크레딧은 @Ruslan에게도 적용됨).댓글란에 이 두 가지 사항에 대한 자세한 내용이 나와 있습니다.
코드가 무엇을 하는지 설명하는 답변이 이미 있지만, 이 게시물은 어떤 이유에서인지 많은 이상한 관심을 받고 있고 잘못된 이유로 반복적으로 닫히고 있기 때문에, 코드가 무엇을 하는지, C가 무엇을 보장하는지, 무엇을 보장하지 않는지에 대한 몇 가지 통찰력이 있습니다.
unsigned long foo = 506097522914230528;
이 * 큰 이 정수 상수는 506 * 10^15 크기입니다.그것은 안에 들어갈 수도 있고 안 들어갈 수도 있습니다.unsigned long
long
시스템에서 4 또는 8바이트 크기입니다(implement화 정의).4
long
이 은 , .0x03020100
1).8
long
* 할 수 이 적합합니다. 18.44 * 10^((unsigned char *) &foo)
는 유효한 포인터 변환 및 잘 정의된 동작입니다.C17 6.3.2.3/7은 다음을 보장합니다.객체 유형의 포인터를 다른 객체 유형의 포인터로 변환할 수 있습니다.참조된 유형에 대해 결과 포인터가 올바르게 정렬되지 않으면 동작이 정의되지 않습니다.그렇지 않으면 다시 변환하면 결과가 원래 포인터와 동일하게 비교됩니다.
문자에 대한 포인터가 있으므로 정렬에 대한 우려는 적용되지 않습니다.
6.3.2.3/7을 계속 읽는다면:
개체에 대한 포인터를 문자 유형에 대한 포인터로 변환하면 결과는 개체의 주소가 가장 낮은 바이트를 가리킵니다.개체 크기까지 연속적으로 증가하는 결과는 개체의 나머지 바이트에 대한 포인터를 산출합니다.
이것은 C의 어떤 타입이든 문자 타입을 통해 검사할 수 있는 특별한 규칙입니다.가 A에가
pointer++
합니다.pointer + i
상관없어. 한 물체 안을 있는 한, 검사된 물체 안을 계속 가리키고 있는 한이i < sizeof(unsigned long)
확실한. 행동입니다.이것은 명확한 행동입니다.언급된 또 다른 특별한 규칙 "엄격한 별칭"은 문자에 대한 유사한 예외를 포함합니다.6.3.2.3/7 규칙과 동기화됩니다.특히 "엄격한 앨리어싱"은 다음을 허용합니다(C17 6.5/7).
개체는 다음 유형 중 하나를 포함하는 l 값 표현으로만 저장된 값에 액세스해야 합니다.
...- 성격 타입
"는 ""입니다.
unsigned long
그리고 보통은 그렇게만 접근할 수 있습니다.제.unsigned char*
께 됩니다를 사용하여 해제됩니다.*
캐릭터 유형으로 접근합니다.위에서 언급한 엄격한 별칭 규칙에 대한 예외로 허용됩니다.로 로, 로, 것입니다.
unsigned char arr[sizeof(long)]
*(unsigned long*)arr
lvalue access는 엄격한 별칭 위반 및 정의되지 않은 동작일 것입니다.하지만 여기서는 그렇지 않습니다.으로.
%u
다 .printf
합니다.unsigned int
그 로.printf
는 가변 함수이며, 이 코드를 잘 정의하게 만드는 몇 가지 오드볼 암시적 촉진 규칙들과 함께 나옵니다.unsigned char
값은 기본 인수 프로모션을2) 통해 다음과 같이 승격됩니다.int
.printf
으로 이시를 다시e합니다. 해석다.int
~하듯이unsigned int
. 우리가 시작했기 때문에 부정적인 값일 수는 없습니다.unsigned char
. 변환은3) 잘 정의되고 휴대성이 뛰어납니다.이렇게 바이트 값을 하나씩 얻습니다.16진수 표현은
07 06 05 04 03 02 01 00
이것이 어떻게 저장되어 있는지는unsigned long
CPU 특정/구현 정의 동작입니다.다음 중 가장 일반적인 FAQ는 무엇입니까? CPU 엔디안은 무엇입니까?여기에는 이 코드와 매우 유사한 예가 포함되어 있습니다.Little endian에 인쇄됩니다.
1 2...
, on big endian it will print7 6...
.
1) See the unsigned integer conversion rule C17 6.3.1.3/2.
2) C17 6.5.2.2/6.
3) C17 6.3.1.3/1 "When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged."
ReferenceURL : https://stackoverflow.com/questions/66226175/indexing-an-unsigned-long-variable-and-printing-the-result
'programing' 카테고리의 다른 글
VBA에서 간단한 문자열을 바이트 배열로 변환하는 방법은? (0) | 2023.10.05 |
---|---|
화살표 함수로 '이것'을 묶을 수 있습니까? (0) | 2023.10.05 |
오류 "adb 연결이 중단되었으며 심각한 오류가 발생했습니다." (0) | 2023.10.05 |
우커머스 체크아웃 청구 발송 필드에서 기본 선택 상태 제거 (0) | 2023.10.05 |
첫번째결과만선택하세요 (0) | 2023.10.05 |