Dá se bitový posun použít na unsigned char? – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Dá se bitový posun použít na unsigned char? – C / C++ – Fórum – Programujte.comDá se bitový posun použít na unsigned char? – C / C++ – Fórum – Programujte.com

 

Spuštěný nový filmový web Filmožrouti.cz — vše o Avengers, Pacific Rim, Thor, Star Wars…
oxidián0
Expert
31. 7. 2017   #1
-
0
-

   

unsigned char buf [1*729];
buf << (shift*18);

Dostal jsem chybovou hlášku:
error: invalid operands to binary << (have 'unsigned char *' and 'int')|


??? unsigned char * se nedá posouvat?
 

Jak dostat 12 integerů to jedné paměti (jednoho čísla)? Rozsah jednoho integeru je 0-199999.

Nahlásit jako SPAM
IP: 78.102.61.–
31. 7. 2017   #2
-
0
-

buf je ukazatel. Dělat bitový posun na ukazateli mi příjde divný. Int na Windows bývá 4 byte. Lze uplatnit bitový posun a bitový součin na int a získat tak jednotlivé byte. Ty pak vkládat do pole char.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
31. 7. 2017   #3
-
0
-

Kromě toho lze pro účely kopírování int do buf přetypovat ukazatel. Pak je výsledek závislý na endianitě.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
oxidián0
Expert
31. 7. 2017   #4
-
0
-

Vložím sem zatím co jsem udělal:

    int lat, lon, line_no, i = 0;
    float f[12];
    unsigned int m[12];
    line_no++;
    fscanf(fp, "%d %d %f %f %f %f %f %f %f %f %f %f %f %f ", &lat, &lon, &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9], &f[10], &f[11]);
    for (i = 0; i<12; i++) {
            f[i]*=100;
            m[i] = (unsigned int) round(f[i])+99999;
        }; free(f);
    for (i = 0; i<sizeof(buf); i++)
        {
        buf[i] <<= 18;
        }
    prinf( "buf[i]  )


Teď bych chtěl zkopírovat ten integer do buf, tedy aby se ty bity/byty z čísla objevily na konci. Jak na to?

Chtěl bych udělat něco takovýho:

for (i = 0; i<12; i++) {
    for (j = 0; j<12; j++) {
        f[j]*=100;
        m[j] = (unsigned int) round(f[j])+99999;
    };
    free(f);
    for (i = 0; i<sizeof(buf); i++)
        buf[i] <<= 18;
    memcpy(buf, (char*)&m[i];, 4); /* although sizeof(int) would be better */
}


Ale problém je v tom že to kopíruje po 4 bytech, ale já potřebuju zkopírovat jen 18 bitů, aby se předchozí bity nepřepsaly

Nahlásit jako SPAM
IP: 78.102.61.–
31. 7. 2017   #5
-
+1
-
Zajímavé

free (f) projde bez chyby? Co vrátí sizeof(buf)? Tipuji 4.  Int po jednotlivých bytech lze do pole typu char vyskládat takto: 

char buf[4];
int cislo;

//from LSB
buf[0] = cislo & 0x000000FF;
buf[1] = (cislo >> 8) & 0x000000FF;
buf[2] = (cislo >>16) & 0x000000FF;
buf[3] = (cislo >>24) & 0x000000FF;

Dalo by se to zpracovat v cyklu.

Nahlásit jako SPAM
IP: 195.178.67.–
31. 7. 2017   #6
-
0
-

   

char buf[4];
int cislo;

memcpy(buf, &cislo, 4);

V závislosti na citlivosti typové kontroly může být nutné oba ukazatele přetypovat na void* ručně. Pořadí bytů v poli závisí na endianitě. Problémy může způsobit i zarovnávání v paměti.

Ještě pozn.: u obou příkladů předpokládám sizeof(int) = 4.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
oxidián0
Expert
31. 7. 2017   #7
-
0
-

#6 hlucheucho
free(f) jsem měl dát až za cyklus.

Spíš bych měl zkopírovat ten byte který přepíšu. Přepisovat bug budu 3 byty od konce. Tzn. 4 byte od konce nebude dotčený. Zkopírovat bych tedy měl 3. byte od konce. To bych udělal. Pak zkopíruju 3 byty z integru do buf od konce. Ale musím ještě provést opravu 3. bytu, tak aby posledních 2 bitů se zkopírovalo (obnovilo).

buf od konce:
nekopíruje se   | 24 bitů se přepíše
87654321      87 654321   87654321   87654321
00000000      11 000000   11111111   11111111
              |----> toto se přepíše
2 bity obnovit->|

zazálohování bych snad mohl udělat takto:

unsigned char backup[3];
memcpy( backup, buf, 3 );

Nahlásit jako SPAM
IP: 78.102.61.–
31. 7. 2017   #8
-
0
-

free (f) na statické pole? Proč?

buf[i] << 18 ... co dostanu, když unsigned char posunu o 18 bitů vlevo?

18 bitů.... je ta komprese nutná? Pokud ano, postupuje se podobně jako u 7-bitového šifrování při kódování PDU.  Jde to skládat pomocí bitových operací posun, OR a AND. Příjde mi to zbytečně komplikované. Proč se data neukládají a nezpracovávají tím nejjednodušším způsobem?

hu

Nahlásit jako SPAM
IP: 195.178.67.–
oxidián0
Expert
31. 7. 2017   #9
-
0
-

#8 hlucheucho
posunem o 18 bitů vlevo dostanu místo abych mohl uložit další číslo. Každé číslo má maximálně 18 bitů.

Aby databáze zabrala co nejméně místa. Spočítal jsem že zkomprimované to bude mít 45MB.

Edit:

Zkusím to udělat jak si to napsal

char buf[4];
int cislo;

//from LSB
buf[0] = cislo & 0x000000FF;
buf[1] = (cislo >> 8) & 0x000000FF;
buf[2] = (cislo >>16) & 0x000000FF;
buf[3] = (cislo >>24) & 0x000000FF;
Nahlásit jako SPAM
IP: 78.102.61.–
31. 7. 2017   #10
-
0
-

... a nezkomprimované 90MB? Na jakém HW a OS to poběží? Jestli Windows a běžný počítač tak je ta komprese nadbytečná. Kromě toho u Windows je k dispozici komprese zip, hotové řešení.

Jinak bych si usnadnil práci a int bych zarovnal na 24 bitů. "Zahodit" byte je snažší než bojovat s bity.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
31. 7. 2017   #11
-
0
-

Vynulovat bity pomoci bitového AND, nastavit pomoci bitového OR.  Složit byte ze dvou částí, kde jedna část má platné MSb následované nulami a druhá část má platné LSb předcházené nulami opět pomocí bitového OR nebo lze i aritmetickým součtem. Pokud budu do bufferu zapisovat komprimovaná čísla od MSB, mohu postupovat asi takto:

1. Posunu int číslo co nejvíce vlevo (o 14 bitů vlevo?), zleva mám 18 bitů následovaných nulami, význam pro mne mají 3 byte, LSB obsahuje 0 a je bezvýznamný
2. 3 platné byte zapíšu do bufferu, poslední z nich obsahuje 2 platné bity na pozici MSB následované (6?) nulami, ty budou při zpracování dalšího čísla nahrazeny.
3. Další číslo posunu vlevo tak aby zůstaly 2 bity MSB nula a následovalo 18 bitů čísla (o 12 bitů vlevo?).
4. První byte čísla pomocí bitového OR přidám na konec třetího byte v bufferu.
5. Další 2 byte čísla kopíruji do buferu. V pátém byte zůstávají na konci (4?) neplatné nuly.
atd.

Ze 4 čísel tak vytvoříš 72 bitů, tj 9 bytů. U pátého čísla začneš od znova akorát zapisuješ do 10 bytu bufferu.

Lze zvětšit efektivitu tím, že datový typ int budeš vnímat jako 24-bitový. 

hu

Nahlásit jako SPAM
IP: 195.178.67.–
oxidián0
Expert
31. 7. 2017   #12
-
0
-

Potřeboval bych poradit proč se nemohu dostat k proměnné buf:

void readfiles(FILES * files){
    unsigned char * buf [1*729];
    readfile(filename, files->pressure[0].skip_lines, buf, shift);
}
int readfile(char * name, int skip, unsigned char * buf, int shift ){
 // buf je (unsigned char *) na adrese 0x22dd18 ""
    printf("buf size %d", sizeof(buf));
}

Vypisuje to, že bug má 4 byty. Stejný příkaz v readfiles ukáže větší kapacitu.

Nahlásit jako SPAM
IP: 78.102.61.–
31. 7. 2017   #13
-
0
-

buf je ukazatel... už jsem to tu někde psal... a ukazatel má zřejmě velikost 4 byty.

hu

Nahlásit jako SPAM
IP: 193.86.81.–
Radek Chalupa
~ Redaktor
+1
Super člen
31. 7. 2017   #14
-
0
-

#12 oxidián
Nevím co je to "příkaz v readfiles", ale operátor sizeof použitý na jakýkoliv ukazatel ti vrátí hodnotu závislou na "bitové šířce" sestavení aplikace, tj. pokud je aplikace sestavená jako 32-bitová, dostaneš 4 a v 64-bitovém sestavení dostaneš 8. Ve 32-bitovém OS samozžejmě 64-bitovou aplikaci nelze spustit, ale v 64-bit OS dostaneš různé hodnoty právě podle sestavení aplikace, takže asi proto ty různé hodnoty.

Radek Chalupa
- individuální konzultace, školení programování, (C/C++, C#, WinAPI, .NET, COM, ATL, MFC...)
- vývoj software na zakázku
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
gna
~ Anonymní uživatel
439 příspěvků
1. 8. 2017   #15
-
0
-

#14 Radek Chalupa

Nevím co je to "příkaz v readfiles",

To by mohl být ten příkaz v té funkci hned na tím.

ale operátor sizeof použitý na jakýkoliv ukazatel ti vrátí...

To už mu hlucheucho napsal.

...dostaneš různé hodnoty právě podle sestavení aplikace, takže asi proto ty různé hodnoty.

Nebo proto, že je to někde pole a jinde jen ten ukazatel?

Hlavně nezapomenout reklamu, snad aspoň plní účel.

Nahlásit jako SPAM
IP: 213.211.51.–
MilanL+1
Super člen
1. 8. 2017   #16
-
0
-

no já bych si to asi drobátko ulehčil:

uložil bych si nejdříve ty spodní 2 Byte od všech 4 INTů a 9 Byte složil z těch 4x 2bity, myslím že je to pro představu jednodušší.
pole char pak bude:
- 8Byte  I0.b0-7,I0.b8-15,I1.b0-7,I1.b8-15,I2.b0-7,I2.b8-15,I3.b0-7,I3.b8-15 
- 9Byte bude složen I3.b16-17 I2.b16-17 I1.b16-17 I0.b16-17

Nahlásit jako SPAM
IP: 91.139.9.–
MilanL+1
Super člen
1. 8. 2017   #17
-
0
-

#16 MilanL
sakra nevložil se mi kod programu :(

unsigned char buf[X];
int bufCount = 0;
unsigned char B9 = 0;

for (i=0; i<12; i++){
	buf[bufCount] = pole[i] & 0x000000FF;
	bufCount++;
	buf[bufCount] = (pole[i] >> 8) & 0x000000FF;
	bufCount++;
 
// pomocí OR přidí k B9 další 2 bity
	B9 |= ((pole[i] >> 16) & 0x00000003) << ((i % 4)*2);

// v každém 4. cyklu je třeba uložit a znulovat B9
	if ((i % 4) == 3){
		buf[bufCount] = B9;
		bufCount++;
		B9 = 0;
	}
}
Nahlásit jako SPAM
IP: 91.139.9.–
MilanL+1
Super člen
1. 8. 2017   #18
-
0
-

#17 MilanL
dekodování 

unsigned char buf[108];  // 12 x 9

for (i=0; i<12; i++){
	int Ctverice = i / 4;
	if ((i % 4)==0) int B9 = buf[Ctverice*9+8];

	pole[i] = buf[Ctverice*9+(i % 4)*2];  
				// index pozice ve čtveřici * 2 byte na int
	pole[i] |= buf[Ctverice*9+(i % 4)*2+1] << 8;

// rotace a vymaskování bitů 16-17 z B9
	pole[i] |= (B9 << (16-(i % 4)*2)) & 0x00030000;
}

EDIT: unsigned char buf[27]; // (12/4) x 9

Nahlásit jako SPAM
IP: 91.139.9.–
1. 8. 2017   #19
-
0
-

Není v tom nějaký háček? Vrtá mi hlavou, proč takovou myšlenku nepoužili když vytvářeli 7-bitové "šifrování" SMS. 

Osobně si myslím, že poskládaný byte by měl jít jako první. Když má pevnou pozici, je snažší pak dekodovat. Měj na paměti, že počet int čísel nemusí být násobkem 9.

Ještě k použití sizeof. Pro velikost polí je to nešikovné. Pokud trváš na čistém C, je třeba funkci předat ukazatel a velikost pole. Pro tyto účely je pak vhodné ke každému poli mít proměnnou obsahující velikost pole. Nebo mít v poli "ukončovací" prvek jako to mají řetězce. V C++ je na místě použití vektoru, ten zná svou velikost i obsazenost.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
MilanL+1
Super člen
1. 8. 2017   #20
-
0
-

#19 hlucheucho
poskládaný na první pozici je taky možnost, jen to drobet zjednoduší dekodování, na druhou stranu je pak třeba si uchovat tu první pozici do proměnné, aby věděl kam se vracet.
jinak stejně by to měl kodovat a dekodovat po těch skupinách 12 intů jak to používá.

Nahlásit jako SPAM
IP: 91.139.9.–
MilanL+1
Super člen
1. 8. 2017   #21
-
0
-

druhá varianta o které jsem přemýšlel byla použít typ long (64bit) a pomocí Hash kodovat po 3 intech
bylo by to kodování (do cca 53bitů) tzn  12 : 7 (28B na 12 intů) místo 16:9 (27B na 12 intů)

samozřejmě místo výpočtu hash lze použít v long rotaci 3x 18 = 54 stále jsme v 7B.

Nahlásit jako SPAM
IP: 91.139.9.–
oxidián0
Expert
2. 8. 2017   #22
-
0
-

Nevšiml jsem si že tu přibily příspěvky a už jdu spát tak teď to nemám čas číst, ale přemýšel jsem o tom a došel jsem k závěru že nejspíš nepotřebuju dělal to takhle složitě. Nejdříve mě napadlo zálohovat 3 byty z integeru pak zkopírovat integer do řetězce. V dalším cyklu obnovit ten přepsaný bit - Viz varianta A) . člen .i označuje pořadové číslo parametru. To co je zakomentované už jsem zavrhl jako zbytečné

A) Zpracovávat čísla do bufferu zprava:
kopírovat od pozice (bod 3):
int pos = files->název_parametru[0].i * 3

NEBO B) KRATŠÍ
ZKOPÍROVAT JENOM TY POTŘEBNÉ BITY!
ŽÁDNÁ ZÁLOHA NENÍ NUTNÁ!!!

// 1) backup bit 3 (counted from right to left)
// int mask &= ~0x3f;
// int backup |= m[i] & 0x3f;
// 2) copy 3 bytes from unsigned int to buf
3) v dalším cyklu zkopírovat další tři bity z čísla do buf
tmp[pos+2] = i & 0xFF;          // první byte
tmp[pos+1] = (i>>8) & 0xFF;  // druhý byte
tmp[pos+0] = (i>>16) & 0x3f; // bit 7 a 8 z třetího bitu
// 4) obnovit zálohu bitů 7 a 8 z 3. bytu na buf

Zbyla mi možnost B). Pokud ten kód mám správně napsaný, z toho integeru se zkopíruje jen 18 bitů zprava doleva. V dalším cyklu budu zase kopírovat, ale tak, aby se nepřepsal ten 18 a 17 bit. Kopírování v druhém cyklu tedy musí být od 19 bitu tj. 18 + 18 = skončí se bitem 36.

**Edit:**

Místo přímého přístupu do bufferu musím k bufferu přistupovat přes pointer. Zkopíruju integer do dočasného char array tmp[3] a toto zkopíruju pomocí memcpy do buf na správnou pozici. Tu pozici v paměti akorád musím vždy nastavit správně.

Nahlásit jako SPAM
IP: 78.102.61.–
MilanL+1
Super člen
3. 8. 2017   #23
-
0
-

#22 oxidián
no nevím ten 3.BYTE máš myslím blbě při >> 16 máš ty původní 2 nejvyšší bity 17 18 na 2 nejnižších.
osobně bych volil spíš tu variantu s longem (64bit), na jednu sadu 12 integerů o 18bitech je rozdíl 1 Byte navíc 

//verze rotace
unsigned char vystup[28];	// 12/3*7 pro 1 záznam
long TMP = 0;

for (int i=0;i<12;i++){
	long poleTMP = pole[i] & 0x000000000003FFFF;  // vymaskování 18bitů
	TMP |= poleTMP << (18*(i % 3);   // rotace 0, 18, 36
	if ((i % 3) ==2){                // po naplnění třemi Inty ulož¨
		int trojice = i / 3;	 // pro výpočet posunu ve výstupním poli
		for (int j=0;j<7;j++)	 // ulož 7 BYTE z LONGU
			vystup[7*trojice+j] = (TMP >> (8*j)) & 0xFF;
		TMP = 0;
	}
}
// verze HASH - pouze 2 malé úpravy
// před smyčku i 0;<12
long ha[3] = {1,200000,40000000000};

// ve smyčce vynechat poleTMP a upravit TMP na
       TMP += pole[i]*ha[(i % 3)];

Nahlásit jako SPAM
IP: 91.139.9.–
3. 8. 2017   #24
-
0
-

Když to tady vidím, tak by bylo nejlepší, co jsem radil někde na začátku: vys... se na nadbytečnou a neúčelnou optimalizaci.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
oxidián0
Expert
3. 8. 2017   #25
-
0
-

#24 hlucheucho
Bude nejlepší když to zkusím udělat po svém. Sice to nebude nejlepší a nejefektivnější, ale bude to něco na čem se to naučím. A pak někdy příště to zas mohu zdokonalit. Je to o samostatném uvažování. Když mi jen napíšete celý kód tak nad tím nebudu přemýšlet a to by byla škoda.

Nahlásit jako SPAM
IP: 78.102.61.–
oxidián0
Expert
3. 8. 2017   #26
-
0
-

#23 MilanL
Díky za kód, já většinou volím vždy tu těžší a komplikovanější cestu. Dřív než v sobotu se k tomu nedostanu.

Nahlásit jako SPAM
IP: 78.102.61.–
MilanL+1
Super člen
4. 8. 2017   #27
-
0
-

#26 oxidián
hlavně si ty algoritmy zkoušej na menším vzorku třeba 10 sad zakodovat a dekodovat, a porovnat jestli na sebe sedí.

Nahlásit jako SPAM
IP: 91.139.9.–
oxidián0
Expert
5. 8. 2017   #28
-
0
-

#27 MilanL
No právě že to chci dělat nejdříve po jednom řádku, ne vše 600000 nebo kolik jich je. Jen mám teď problém zase začít po pauze a v těch vedrech se mi nic nechce dělat.

Nahlásit jako SPAM
IP: 78.102.61.–
oxidián0
Expert
6. 8. 2017   #29
-
0
-

#23 MilanL
Další možnost, která mě napadla:

rozdělit těch 12 cyklů na 3 cykly. V každém cyklu proběhne toto:

1. do proměnné number typu long double (tj. 10 bytů) zkopíruju 4 čísla tak, že tam pošlu

18 bitů, shift, dalších 18 bitů, shift, dalších 18 bitů, shift, dalších 18 bitů.

Ve výsledku bych pokryl 72 bitů, tj 9 bytů.

2. z proměnné number zkopíruju 9 bytů do buf.

To celé se opakuje třikrát.

Edit:

Akorád je problém že mi to nejde zkopírovat:

    number |= m[i];
    number = m[i] << 18.0l;

dostávám chyby:

error: invalid operands to binary | (have 'long double' and 'long double')|
error: invalid operands to binary << (have 'long double' and 'long double')|

Nahlásit jako SPAM
IP: 78.102.61.–
MilanL+1
Super člen
12. 9. 2017   #30
-
0
-

#29 oxidián
nemůžeš použít bitové operace na float typy

Nahlásit jako SPAM
IP: 91.139.9.–
Zjistit počet nových příspěvků

Přidej příspěvek

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 62 hostů

Podobná vlákna

Bitový zápis, posun — založil crazy

Unsigned char — založil oxidián

Base64 bez unsigned char — založil etrix

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032017 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý