Grimnar_ Skrevet 28. november 2011 Del Skrevet 28. november 2011 Sitter å leser en kode der jeg kom over dette: void func(unsigned int *foo) { double bar; .... .... .... *(unsigned long *)foo = (unsigned long)bar; } Sliter litt med å se greia til denne: *(unsigned long *)foo og hvordan denne brukes utenfor funksjonen. Noen som kan forklare? Lenke til kommentar
TheMaister Skrevet 28. november 2011 Del Skrevet 28. november 2011 (endret) Bare å begynne å løpe. Koden er ikke lovlig i det hele tatt og vil muligens kræsje hardt. Vel, *(unsigned long*)foo = bar; betyr at foo castes til en peker til unsigned long, der innholdet av hva foo peker på blir satt til bar, som om det var en long, og ikke unsigned int. En annen måte å skrive det på er: unsigned long *foo_long = (unsigned long*)foo; // OBSOBSOBSOBSOBS skummelt! *foo_long = bar; Koden vil sikkert kjøre fint på Windows, men vil ikke fungere som planlagt på Linux og OSX 64-bit er long er 64-bit og ikke 32-bit. (Hvorfor i all verden skriver folk kode som dette? Vi er i 2011, ikke 1999 ... <_<) Endret 28. november 2011 av TheMaister Lenke til kommentar
GeirGrusom Skrevet 28. november 2011 Del Skrevet 28. november 2011 Det vil vel funke det. Standard oppførsel for å caste double til unsigned long vil vel være trunkering. Men en vil vel få en warning ettersom double er 64-bit og unsigned long i nåværende GCC og Visual C++ er 32-bit på både 64-bit og 32-bit mål. Lenke til kommentar
TheMaister Skrevet 28. november 2011 Del Skrevet 28. november 2011 double -> long er ikke akkurat problemet her, pointer-alias er et ganske stort problem. Lenke til kommentar
Grimnar_ Skrevet 28. november 2011 Forfatter Del Skrevet 28. november 2011 Pointer alias som å ha to pekere til samme plassering i minne? Litt usikker på hvordan denne "foo" blir brukt videre, men jeg kan jeg anta at den er lagd slik for å kunne "hentes" fra andre metoder i programmet? Lenke til kommentar
GeirGrusom Skrevet 28. november 2011 Del Skrevet 28. november 2011 double -> long er ikke akkurat problemet her, pointer-alias er et ganske stort problem. Ah det var en detalj som gikk meg hus forbi. Da er jeg helt enig i ditt utsagn ^^ Lenke til kommentar
TheMaister Skrevet 28. november 2011 Del Skrevet 28. november 2011 Pointer alias som å ha to pekere til samme plassering i minne? Litt usikker på hvordan denne "foo" blir brukt videre, men jeg kan jeg anta at den er lagd slik for å kunne "hentes" fra andre metoder i programmet? I C betyr pointer-alias at en blokk med minne blir pekt på av to eller flere pekere av ikke-kompatible typer. Det er skummelt og kan forårsake "morsomme" bugs. unsigned int *foo; er en peker som peker på unsigned int. Når da pekeren blir castet til unsigned long*, en ikke kompatibel type, har vi pointer-alias. Hva som skjer da er ikke definert av C-standarden. Typisk går det bra, men har vært borti flere tilfeller der koden ikke virker i det hele tatt med kraftig optimisering. Lenke til kommentar
☀ ❄ Skrevet 28. november 2011 Del Skrevet 28. november 2011 (Hvorfor i all verden skriver folk kode som dette? Vi er i 2011, ikke 1999 ... <_<) Men kanskje koden er skrevet i 1999 Litt usikker på hvordan denne "foo" blir brukt videre, men jeg kan jeg anta at den er lagd slik for å kunne "hentes" fra andre metoder i programmet? Peker til en lokal variabel som har gått ut av skop? Dårlig bissniss, bedre kjent som undefined behavior. (Med unntak av i C++98/03 og C++0xb, hvor det er gyldig å referere til en lokal variabel returnert som reference-to-const, så lenge referansen eksisterer.) I C og C++ heter det forresten funksjoner (og medlemsfunksjoner). Lenke til kommentar
LostOblivion Skrevet 29. november 2011 Del Skrevet 29. november 2011 Dette er nettopp hvorfor de fleste unngår rotete språk som C og C++ om de kan, de er rett og slett alt for svakt typet, noe som er farlig om du ikke vet hva du driver med. 1 Lenke til kommentar
torbjørn marø Skrevet 30. november 2011 Del Skrevet 30. november 2011 C/C++ er ikke problemløsning, det er problemskaping Lenke til kommentar
GeirGrusom Skrevet 30. november 2011 Del Skrevet 30. november 2011 Datatypene er på en måte litt tåpelig definert. Grunnen er at alle er definert i forhold til hverandre. char skal være minste adresserbare størrelse (mulig denne er definert til 1-byte) short må være større enn char (vanligvis 2 byte) int må være større eller lik short (vanligvis 4 byte) long må være større eller lik int (på GCC under 64-bit kan denne være 64-bit, i Visual C++ og open Watcom er den alltid 32-bit) long long må være større eller lik long (sannsynligvis 64-bit i både 32-bit og 64-bit kompilatorer) float er 32-bit double er 64-bit long double er større eller lik double (standard oppførsel i GCC er at denne blir 128-bit, men dette kan variere. I VC++ er den synonymt med double) Innen ting som skal brukes på tvers av programmer (som biblioteker etc) kan det være bedre å bruke int32_t og lignende (definert i C99) istedet ettersom C og C++ har en litt skrullete definisjon på datatypestørrelser. Lenke til kommentar
TheMaister Skrevet 30. november 2011 Del Skrevet 30. november 2011 long long må være større eller lik long (sannsynligvis 64-bit i både 32-bit og 64-bit kompilatorer) Innen ting som skal brukes på tvers av programmer (som biblioteker etc) kan det være bedre å bruke int32_t og lignende (definert i C99) istedet ettersom C og C++ har en litt skrullete definisjon på datatypestørrelser. long long må være minst 64-bit, og større eller like stor som long. <stdint.h> er her for en grunn. Kode som ikke bruker int/uint*_t (eller tilsvarende) for størrelser som skal ha et visst antall bytes er broken. Har vært borti alt for mange tilfeller der kode har gått ut i fra at long er 32-bit. Dette ser jeg omtrent bare i Windows-kode (morsomt å porte slik kode), så kan være noe der at MSVC ikke fikk stdint.h før i 2010! Grunnen til at C er veldig vag på dette med størrelser er for at man skal kunne implementere C effektivt på veldig merkelige systemer. Husk at CHAR_BIT ikke _må_ være 8. Noen maskiner som har 19-bit ord, osv, men det ser man nok ganske sjeldent i dag (heldigvis). Hver gang man skriver short eller long bør man tenke seg godt om. 1 Lenke til kommentar
GeirGrusom Skrevet 30. november 2011 Del Skrevet 30. november 2011 <stdint.h> er her for en grunn. Kode som ikke bruker int/uint*_t (eller tilsvarende) for størrelser som skal ha et visst antall bytes er broken. Har vært borti alt for mange tilfeller der kode har gått ut i fra at long er 32-bit. Dette ser jeg omtrent bare i Windows-kode (morsomt å porte slik kode), så kan være noe der at MSVC ikke fikk stdint.h før i 2010! Win32 forventer i stor grad at long er 32-bit, og det er langt ifra det eneste. Dette er noe jeg har sett i ustrakt grad, og det er langt ifra bare Windows dette er et faktum på. Libvorbis er et eksempel. Lenke til kommentar
☀ ❄ Skrevet 30. november 2011 Del Skrevet 30. november 2011 (endret) Dette er nettopp hvorfor de fleste unngår rotete språk som C og C++ om de kan, de er rett og slett alt for svakt typet, noe som er farlig om du ikke vet hva du driver med. C++ er ganske sterkt typet. Ikke Haskell-style, riktignok, men adskillig sterkere typet enn f.eks. Python, Ruby, JavaScript og andre utbredte språk. Grunnen til at de fleste har problemer med C og C++ er at de ikke lærer seg teknikker som gjør koden langt sikrere. Man må ta C og C++ som det de er, ikke som om de var Ada. (I C++0xb kan man for øvrig nærmest velge bort alle de "grisete detaljene".) Man bør ikke skrive produksjonskode i noe språk uten at man vet hva man driver med. C og C++ velger å stole på programmereren, med den konsekvens at koden er raskere men potensielt mer lumsk. Som nevnt av andre bør man uansett bruke <stddef.h> / <cstddef> hvis koden på noen som helst måte kan være avhengig av representasjonen til en type. C/C++ er ikke problemløsning, det er problemskaping Jeg tror ikke du egentlig mener det. Jeg tror du skjønner at man bør bruke rett verktøy for rett oppgave, og at i enkelte tilfeller er det C eller C++ som er det verktøyet, mens det i andre tilfeller er andre verktøy som er bedre egnet. Det er for øvrig en grunn til at f.eks. Google og Facebook satser kraftig på C++, og at Microsoft gjenopptar C++-tråden sin i stor grad. char skal være minste adresserbare størrelse (mulig denne er definert til 1-byte) Jepp, sizeof(char) er garantert alltid, alltid lik 1 (byte), uten noen unntak noensinne. Som nevnt av noen andre har man derimot ingen garanti for at dette er åtte bit. short må være større enn char (vanligvis 2 byte) int må være større eller lik short (vanligvis 4 byte) long må være større eller lik int (på GCC under 64-bit kan denne være 64-bit, i Visual C++ og open Watcom er den alltid 32-bit) long long må være større eller lik long (sannsynligvis 64-bit i både 32-bit og 64-bit kompilatorer) Dette er definert som minimumsspenn av verdier som hver type er nødt til å kunne representere. Se f.eks. side 22 i C99-spesifikasjonen. long long må for øvrig være ekte større enn long. Edit: Fant ikke noe som underbygger dette i standarden, så det kan være at kilden min tar feil. Men long long må minimum kunne representere +/- 2^63 − 1. Innen ting som skal brukes på tvers av programmer (som biblioteker etc) kan det være bedre å bruke int32_t og lignende (definert i C99) istedet [...] Definitivt! C++0xb har også disse typene. Win32 forventer i stor grad at long er 32-bit, og det er langt ifra det eneste. Dette er noe jeg har sett i ustrakt grad, og det er langt ifra bare Windows dette er et faktum på. Libvorbis er et eksempel. En grei antakelse. Og man vil jo aldri trenge mer enn maksimalt fire gigabyte minne... Endret 30. november 2011 av Lstor Lenke til kommentar
TheMaister Skrevet 30. november 2011 Del Skrevet 30. november 2011 (endret) En grei antakelse. Og man vil jo aldri trenge mer enn maksimalt fire gigabyte minne... Fra tid til annen snubler jeg over slik kode: void *ptr = somedata; unsigned int bar = (unsigned int)ptr; .__. Morro å finne slike bugs klokka 2 på natta, ja Endret 30. november 2011 av TheMaister Lenke til kommentar
GeirGrusom Skrevet 30. november 2011 Del Skrevet 30. november 2011 (endret) Dette er også en feil jeg ser til stadighet: size_t some_size = foo(); auto size = (unsigned int)some_size; edit: men det er vel i 100% av praktiske tilfeller helt ufarlig. Endret 30. november 2011 av GeirGrusom Lenke til kommentar
TheMaister Skrevet 2. desember 2011 Del Skrevet 2. desember 2011 Sant nok, men de skjer! Hadde en bug selv der en bruker ville allokere 8GB, og på et stadie brukte jeg unsigned istedenfor size_t. Er enda mer forsiktig med å bruke size_t nå. Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå