32/64 bit?

 ( begyu | 2009. május 3., vasárnap - 19:13 )

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ás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

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.

Ez sosem szegyen, mint ahogy tanulni sem az.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.