Wiem, że aby uzyskać liczbę bajtów używanych przez typ zmiennej, można użyć na przykład sizeof(int)
. W jaki sposób otrzymasz wartość poszczególnych bajtów używanych podczas zapisywania liczby z tym typem zmiennej? (Tj int x = 125
.)Jak uzyskać wartość poszczególnych bajtów zmiennej?
Odpowiedz
można uzyskać za pomocą bajtów trochę arytmetyki wskaźników:
int x = 12578329; // 0xBFEE19
for (size_t i = 0; i < sizeof(x); ++i) {
// Convert to unsigned char* because a char is 1 byte in size.
// That is guaranteed by the standard.
// Note that is it NOT required to be 8 bits in size.
unsigned char byte = *((unsigned char *)&x + i);
printf("Byte %d = %u\n", i, (unsigned)byte);
}
Na moim komputerze (Intel x86-64), wyjście jest:
Byte 0 = 25 // 0x19
Byte 1 = 238 // 0xEE
Byte 2 = 191 // 0xBF
Byte 3 = 0 // 0x00
Jeśli chcesz uzyskać te informacje, powiedzmy:
int value = -278;
(Wybrałem tę wartość, ponieważ nie jest bardzo interesujące ing dla 125 - najmniej znaczący bajt jest 125, a pozostałe bajty są wszystkie 0)
Najpierw trzeba wskaźnik do tej wartości:
int* pointer = &value;
Teraz można typecast, że do „char” wskaźnik! który jest tylko jeden bajt i pobiera poszczególne bajty przez indeksowanie.
for (int i = 0; i < sizeof(value); i++) {
char thisbyte = *(((char*) pointer) + i);
// do whatever processing you want.
}
Zauważ, że kolejność bajtów na int i innych typów danych zależy od systemu - look up „grubokońcej” vs „little-endian”.
Czy istnieje jakikolwiek powód używania arytmetyki wskaźnika ręcznego zamiast znacznie bardziej czytelnego dostępu do tablicy? –
Ponieważ jest to oczywiste dla tych, którzy są wykształceni, ponieważ używamy wskaźnika? Nie uważam arytmetycznej wskaźnika za błędną lub nieczytelną. – Dan
To nie jest złe, ale z pewnością nie twierdzisz, że jest tak czytelny jak dostęp do tablicy ...! Porównaj '* (x + i)' z 'x [i]'. W rzeczywistości, dlaczego w ogóle istnieje składnia dostępu do tablicy, jeśli nie używamy jej w razie potrzeby? –
To powinno działać:
int x = 125;
unsigned char *bytes = (unsigned char *) (&x);
unsigned char byte0 = bytes[0];
unsigned char byte1 = bytes[1];
...
unsigned char byteN = bytes[sizeof(int) - 1];
Ale należy pamiętać, że kolejność bajtów liczb całkowitych jest platforma zależne.
Zamawianie bajtów zależy od procesora, nie zależy od systemu operacyjnego. – DipSwitch
@DipSwitch Masz rację. Poprawione. –
Można skorzystać z union
ale należy pamiętać, że kolejność bajtów jest procesor zależne i nazywa endianness http://en.wikipedia.org/wiki/Endianness
#include <stdio.h>
#include <stdint.h>
union my_int {
int val;
uint8_t bytes[sizeof(int)];
};
int main(int argc, char** argv) {
union my_int mi;
int idx;
mi.val = 128;
for (idx = 0; idx < sizeof(int); idx++)
printf("byte %d = %hhu\n", idx, mi.bytes[idx]);
return 0;
}
@WTP ah lol, nawet nie zauważyłem: p – DipSwitch
Musisz znać liczbę bitów (często 8) w każdym „bajt ". Następnie możesz wyodrębnić każdy bajt po kolei, używając AND z odpowiednią maską. Wyobraźmy sobie, że int ma 32 bity, a następnie dostać 4 bajty z the_int:
int a = (the_int >> 24) & 0xff; // high-order (leftmost) byte: bits 24-31
int b = (the_int >> 16) & 0xff; // next byte, counting from left: bits 16-23
int c = (the_int >> 8) & 0xff; // next byte, bits 8-15
int d = the_int & 0xff; // low-order byte: bits 0-7
I to wszystko: każdy bajt jest w niskim rzędu 8 bitów a, b, c i d.
Robisz to trudniej niż jest, a używanie przesuwania do wyodrębniania bajtów jest raczej obciążające procesor. Byłoby o wiele prostsze i szybsze uzyskanie dostępu do każdej bajtowej lokalizacji bezpośrednio w pamięci ... – DipSwitch
@Dip - mój brutalny sposób ma zaletę, że jest przenośny w procesorach, podczas gdy inne mogą nie być. Ale jak chcesz, oczywiście. –
+1: Uważam, że jest to o wiele lepsze niż manipulowanie z lokalizacją w pamięci. 1) jeśli jest agnostykiem endi. 2) Procesor może wykonywać operacje w rejestrach procesorów, więc zwykle jest znacznie bardziej wydajny. W rzeczywistości, dla niektórych (8-bitowych) maszyn, może to nie generować żadnego kodu (jeśli masz porządny kompilator). – Lindydancer
Jak 4294967278 to bajt? Domyślny typ 'char' jest prawdopodobnie podpisany w twoim systemie, a rzutowanie na' unsigned' daje duże liczby. –
@Eser Aygün Zaktualizuję kod. Dziękuję za komentarz. –
Czy istnieje jakikolwiek powód używania arytmetyki wskaźnika ręcznego zamiast znacznie bardziej czytelnego dostępu do tablicy? –