32/64 bit?

Fórumok

Hi!
Az alábbi kódban:

static inline uint64_t be64_to_cpu(uint64_t *y)
{
int n = 1 ;
if(*(char *) &n == 1) // True if the cpu is little endian.
{
*y = (*y>>56) |
((*y<<40) & 0x00FF000000000000) |
((*y<<24) & 0x0000FF0000000000) |
((*y<<8) & 0x000000FF00000000) |
((*y>>8) & 0x00000000FF000000) |
((*y>>24) & 0x0000000000FF0000) |
((*y>>40) & 0x000000000000FF00) |
(*y<<56);
}
return *y;
}

az "((*y<<40) & 0x00FF000000000000) |" sorra a gcc a következő hibát adja:
integer constant is too large for 'long' type

Nem igazán tudom, hogy miért nem jó ez egy "unsigned long" típusú változónak.

Hozzászólások

Nem igazán tudom, hogy miért nem jó ez egy "unsigned long" típusú változónak.
64bites rendszer alatt (ha az inttypes.h-t inkludolod), akkor teljesen jo.

32bites rendszer alatt valoban warning jon, ekkor tegye'l egy LL vegzodest a szamok (konstansok) utan: 0x00FF000000000000LL. So"t, az ULL me'g jobb (hangsulyozod hogy unsigned). talan a legjobb az, ha ezt me'g (maga't a konstanst) uint64_t-re kasztolod me'g a & mu"velet elo"tt. ha nagyon peda'ns akarsz lenni (hasznalsz -Wall, -ansi, ... kapcsolokat), akkor hogy ne nyu"gjon a fordito semmit, forditsd -Wno-long-long-gal (a fenti pendans kapcsolok utan add a't a cmdline-ba).

off

Ha a code tag-et használod, megmarad a formázás, és könnyebben olvasható a példakód.

/off

1.

C89 fordító nem köteles olyan integer konstanst elfogadni, ami

long unsigned

-be nem fér bele.

C99 fordító nem köteles olyen integer konstanst elfogadni, ami

long long unsigned

-be nem fér bele.

Bármelyik felismerheti valamilyen extended integer type-ként értelmezhető konstansként (pl. C89 esetén

long long

), de nem köteles.

A jelen C++ szabvány a C89-re épül.

Valószínűleg C89 módot vagy C++-t használsz, és a

long unsigned

-odba nem fér bele a konstans.

Ilyen konstanst C99 módban minden további nélkül leírhatsz (érdemes azért az

LLU

szuffixet odaírni, hogy garantáltan előjel nélküli legyen). Puszta C89-ben (hordozható kódban) egyáltalán nem írhatod le, még kifejezésként sem (nem biztos, hogy létezik bármilyen egész típus, amelyben elfér). C++-ban, úgy vélem, szintén ez a helyzet.

Ha C89-ben dolgozol, és a platformod támogatja a Single Unix Specification Version 2-t, akkor az <inttypes.h>

#include

-olása után a konstanst kifejezésként hordozhatóan (legalábbis SUSv2 platformok számára hordozhatóan) előállíthatod így:

uint64_t magic
    = (uint64_t)0x01234567lu << 32 | (uint64_t)0x89ABCDEFlu;

2.

Ilyet szerintem ne írj le többet (hordozhatónak szánt kódban):

*(char *) &n

ahol

n

típusa

int

. Ha

char

valójában

signed char

, simán signed overflow-hoz vezethet, az meg undefined behavior. Alapvetően nem mentség, hogy előtte

n = 1;

szerepelt; most így nekifutásból, pongyolán tárgyalva, pusztán C89-ben maradva, nem tudom általában véve kizárni, hogy az

int

-ben padding bitek legyenek, amelyeknek akármi is lehet az értéke. Ha nagyon muszáj, akkor

unsigned char *

-on keresztül érd el, az mindig definiált (object representation) hozzáférés, de az érték akármi is lehet. (A kettes komplemens ábrázolás sem garantált, például.)

Lehet, hogy ahol használtad, ott megbízható; nekem mindenesetre bántja a szememet.

3.

A konkrét célra -- vagyis network byte order-ből (= big endian-ból, MSB-ből) host byte order-be konvertálásra -- ugye 32 bites és 16 bites előjel nélküli egészeknél elérhető az

ntohl()

és az

ntohs()

. 64 bitesekhez tudtommal nincs ilyen hordozható függvény, ezért valóban szükséges lehet írni egyet. Ekkor viszont a bemenő paramétert ne a shift operátorokkal érd el, hiszen azok a host byte order szerint dolgoznak, neked pedig csak egy network byte order szerint kitöltött

uint8_t buffer[8]

-ad van, amit véletlenül egy

uint64_t

-be olvastál be. Ennek megfelelően, SUSv2-re gondolva:


uint64_t ntohu64(uint64_t netu64)
{
  uint8_t *n = (uint8_t *)&netu64;

  return
        (uint64_t)n[0] << 56
      | (uint64_t)n[1] << 48
      | (uint64_t)n[2] << 40
      | (uint64_t)n[3] << 32
      | (uint64_t)n[4] << 24
      | (uint64_t)n[5] << 16
      | (uint64_t)n[6] <<  8
      | (uint64_t)n[7];
}

(A szignatúrán még lehet reszelni, próbáltam a meglévők mintájára.)

Ha az elején ellenőrizni akarod, hogy kell-e egyáltalán használnod, akkor (kihasználva, hogy a fenti

magic

-ban a byte-ok mind páronként különbözők):


ntohu64(magic) == magic

Ha valaki tud pontosítani, ne habozzon!

Köszönöm a kimerítő válaszokat! Ezekből sajnos az is kiderült, hogy mennyire tudatlan vagyok.