/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
long -> char casting
Fra : Jesper Gødvad


Dato : 15-05-01 18:58

Hejsa

Er der en venlig person der kan hjælpe mig med følgende konvertering:

Jeg har et tal der er repræsenteret som tekst, fx:

std::string tal = "123456" // et eller andet tal

Tallet skal konverteres til en long - det kan jeg godt finde udaf, men jeg
skal ikke bruge long værdien til noget.
I stedet har jeg brug for en ny streng der er 4 chars lang og repræsenterer
værdien. Altså en long gemt som en char[4].

mvh. Jesper



 
 
Igor V. Rafienko (15-05-2001)
Kommentar
Fra : Igor V. Rafienko


Dato : 15-05-01 19:50

* Jesper Gødvad

> Er der en venlig person der kan hjælpe mig med følgende
> konvertering:
>
> Jeg har et tal der er repræsenteret som tekst, fx:
>
> std::string tal = "123456" // et eller andet tal
>
> Tallet skal konverteres til en long - det kan jeg godt finde udaf,


jøss, folk har begynt å lære (det er ikke vondt ment).


> men jeg skal ikke bruge long værdien til noget.


Hva skal du med konverteringen da? :)


> I stedet har jeg brug for en ny streng der er 4 chars lang og
> repræsenterer værdien. Altså en long gemt som en char[4].


Jeg antar at du vil ha vanlig 2'er komplement representasjon av det
tallet stappet i en char[4]. Et viktig spørsmål er i hvilken
_rekkefølge_ du vil skrive til char[4] -- big eller little endian
(populært kalt på norsk "stor/liten indianer") eller noe annet?

Det er i utgangspunktet ikke gitt at en long får plass i 4 chars, så
det er nok lurere å plassere denne i en char[ sizeof( long ) ].

Det er flere måter å gjøre det på (utgangspunktet er denne teksten):

string num = "123456";


* quick-and-ugly (som ikke er garantert til å fungere, men jeg har
vansker med å forestille meg en arkitektur der denne metoden ikke
vil fungere):

char buf[ sizeof( long ) ]; // long's representation
long f = stream_cast< long >( num ); // convert to float
memmove( buf, &f, sizeof f ); // raw memory dump of float

* not-so-quick and not-so-ugly: ideen er den samme, men denne gangen
bruker vi en union:

union binfloat {
char representation[ sizeof( long ) ];
long num;
} number;

char buf[ sizeof( long ) ];
number.num = stream_cast< long >( num );
memmove( buf, number.representation, sizeof number.representation );

I dette tilfellet er ikke det nødvendig å kopiere til buf (det er
heller ikke nødvendig å definere buf).

* "the bitset trick": denne gjør ikke helt det du _egentlig_ har spurt
etter, men noenlunde tilsvarende ting oppnås likevel:

bitset< sizeof( long ) * CHAR_BIT > b( stream_cast< long >( num ) );
string s = b.to_string< char, traits< char >, string :: allocator >();

(herregud jeg hater denne funksjonen i bitset).

Etter litt "bit-fiddling" (jeg forstår godt hvorfor begrepet har fått
negativ toning), kan man prøve noe sånt:

$ ./a.out 123456
printraw: |00000000000000011110001001000000|
printbuf: |00000000000000011110001001000000|
printbuf: |00000000000000011110001001000000|
printbitset: |00000000000000011110001001000000|
$

Den første linjen genereres av denne funksjonen:

void
printraw( long t )
{
cout << "printraw:\t |";
for ( int i = sizeof t * CHAR_BIT - 1; i >= 0; --i )
   cout << ((t & (1U << i)) ? "1" : "0");
cout << "|\n";
}

og er en "raw memory dump" av det heltallet som gis som argument. Den
De 2 midterste genereres av denne funksjonen:

void
printbuf( char s[], size_t size )
{
cout << "printbuf:\t |";

for ( size_t i = 0; i != size; ++i )
   for ( int j = CHAR_BIT-1; j >= 0; --j )
    cout << ((s[i] & (1U << j)) ? "1" : "0");

cout << "|\n";
}

og er ment til å skrive ut char[4] bit etter bit.

stream_cast er "lånt" av Dietmar Kuehl:

template <typename To, typename From>
To stream_cast(From const& from) {
stringstream stream;
stream << from;
To to;
stream >> to;
return to;
}


Men, av ren nysgjerrighet -- hva skal du med dette?





ivr, som søker enhver unnskyldning til å ikke lese på relasjonsalgebra.
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing.
                  -- Dick Brandon

Mogens Hansen (15-05-2001)
Kommentar
Fra : Mogens Hansen


Dato : 15-05-01 19:58

Hej Igor,
"Igor V. Rafienko" <igorr@ifi.uio.no> wrote in message
news:xjvheymigzw.fsf@gjallarbru.ifi.uio.no...
>
> union binfloat {
> char representation[ sizeof( long ) ];
> long num;
> } number;
>
> char buf[ sizeof( long ) ];
> number.num = stream_cast< long >( num );
> memmove( buf, number.representation, sizeof number.representation );
>

Så vidt jeg husker, så er det "undefined behaviour" i C89 og C++, men
"implementation defined behaviour" i C99 at bruge en union på den måde.
Det er dog ikke ualmindeligt at se den slag konstruktioner, og heller ikke
ualmindeligt at det virker. At noget virker ligger inden for hvad der er
tilladt i "undefined behaviour" :)

Venlig hilsen

Mogens Hansen



Igor V. Rafienko (15-05-2001)
Kommentar
Fra : Igor V. Rafienko


Dato : 15-05-01 20:11

* Mogens Hansen

> > union binfloat {


ehh -- det skulle være "binlong", såklart.


> > char representation[ sizeof( long ) ];
> > long num;
> > } number;
> >
> > char buf[ sizeof( long ) ];
> > number.num = stream_cast< long >( num );
> > memmove( buf, number.representation, sizeof number.representation );
>
> Så vidt jeg husker, så er det "undefined behaviour" i C89 og C++,
> men "implementation defined behaviour" i C99 at bruge en union på
> den måde.


Hmm:

In a union, at most one of the data members can be active at any time,
that is, the value of at most one of the data members can be stored in
a union at any time.

Jeg orker ikke å krangle på hvorvidt et brudd på dette er
undefined/unspecified/implementation-defined. Tja, dette ser grimt ut.


> Det er dog ikke ualmindeligt at se den slag konstruktioner, og
> heller ikke ualmindeligt at det virker. At noget virker ligger inden
> for hvad der er tilladt i "undefined behaviour" :)


:) Jeg innbiller meg at en union blir ganske så _meningsløs_, dersom
implementasjonen gjør noe morsomt i konstruksjonen over, men strengt
tatt har du rett.

Da er det avgjort -- bitset< sizeof( long ) * CHAR_BIT >.

Takk for rettelsen,





ivr, en union kan faktisk ha member functions -- tøft! (nyttig? neppe).
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing.
                  -- Dick Brandon

Mogens Hansen (15-05-2001)
Kommentar
Fra : Mogens Hansen


Dato : 15-05-01 20:10

Hej Igor,
>
> * quick-and-ugly (som ikke er garantert til å fungere, men jeg har
> vansker med å forestille meg en arkitektur der denne metoden ikke
> vil fungere):
>
> char buf[ sizeof( long ) ]; // long's representation
> long f = stream_cast< long >( num ); // convert to float
> memmove( buf, &f, sizeof f ); // raw memory dump of float

Jo, det er faktisk garanteret at det virker (i C++, og formodentlig også C).
Se ISO C++ Standard §3.9

Venlig hilsen

Mogens Hansen

>
>
> ivr, som søker enhver unnskyldning til å ikke lese på relasjonsalgebra.
Os se så at få læst!!!



Jesper Gødvad (15-05-2001)
Kommentar
Fra : Jesper Gødvad


Dato : 15-05-01 22:52


"Igor V. Rafienko" <igorr@ifi.uio.no> wrote in message
news:xjvheymigzw.fsf@gjallarbru.ifi.uio.no...
> * Jesper Gødvad
>
> > std::string tal = "123456" // et eller andet tal
> > Tallet skal konverteres til en long - det kan jeg godt finde udaf,
> jøss, folk har begynt å lære (det er ikke vondt ment).

Ja, men det ville være rart hvis der var en nemmere måde

> > men jeg skal ikke bruge long værdien til noget.
> Hva skal du med konverteringen da? :)
[eksempler som jeg først forstår senere, i morgen eller om nogle år]
> Men, av ren nysgjerrighet -- hva skal du med dette?

Ak, jeg sidder og programmerer et distribueret database system fra grunden.
Det er en opgave på datamatikeruddannelsen, som jeg kan se jeg ikke er den
eneste der kæmper med udfra andre spørgemål i denne newsgroup.Det bliver en
længere forklaring, men du er jo selv ude om det.

Klienten sender en sql-streng, som min server lexikerer og gemmer i
henholdsvis 'symboltabel' og 'symbolliste'. Symbol-tabellen indeholder som
default de reseverede ord og operatorer, fx:

type, værdi
------------
ord, SELECT
ord, CREATE
ord, TABLE
[...]
operator, =
operator, *

Når lexeren støder på elementer der ikke findes i symboltabellen i forvejen
tilføjes de i enden vector<tabelObjekt>.push_back(<tabelObjekt>) .

Rækkefølgen huskes i en symbolliste der er en list<int> . Hvis vi
forestiller os, at der er 20 reserverede ord og operatorer kunne resultatet
være følgende:

sql: SELECT KUNDER.NAVN, KUNDER.ID FROM KUNDER
liste: 1, 21, 22, 21, 23, 5, 21

Hvor tallet 21 svarer til tabelnavnet 'kunder'.

Da jeg har enumerations til samtlige reserverede ord kan jeg i parseren
slippe for at foretage en string-compare og i stedet:
symbolliste::iterator i;
if ( *i == reSelect ) {
if ( *i > antalReserveredeOrd && tabel[*i].type == enumOrd ) {
cout << "Der står SELECT efterfulgt af et gyldigt tabelnavn";

( Du kan nok gætte hvad jeg skulle bruge distance() til nu )

Når parseren (som eksisterer på serveren sammen med lexeren) har
syntax-checket sql-udtrykket skal jeg sende kommandoen videre den den eller
de tabelservere der indeholder den/de berørte tabeller. Jeg kunne
selvfølgelig sende hele den kontrollerede symbolliste / symboltabel, men da
serveren alligevel skal have et skema over hvor de forskellige tabeller og
felter befinder sig kan jeg lige så godt gøre det nemt for mig selv at kode
tabelserveren og sende det i protokolform.

Streng til tabelserver:
kode: #1, #2, #10, #3, #1, #10, #3, #2
oversat: SELECT, [AntalFelter], { [tabelServerNummer], [tabelNummer],
[feltNummer] }

På tabelserveren kan jeg så igen bruge mine enumerations

if ( modtagetStrengOverNet.at(0) == reSelect ) {
int feltStart;
for ( int i = 0; i < modtagetStrengOverNet.at(1); i++ ) {
feltStart = ( i * 3 ) + 1;
// tabelnummer står på feltStart +1
// feltnummer står på feltStart +2
}
}

Så langt, så godt...

I tilfælde som CREATE TABLE kunder, SELECT ... WHERE navn = 'Svendsen' er
jeg tvunget til at overføre selve strengen, men det gør ikke noget for jeg
ved jvf. min protokol at der skal stå en streng. Derfor tilføjer jeg
(char) streng.size() foran strengen, så jeg ved hvor næste element
starter.

MEN! (nu kommer pointen)
Når jeg så skal sende en int, som fx. WHERE id = 123456 vil jeg sende den
som en 32 bit integer / long.
Ligeledes vil jeg kun have en 4 byte/char repræsentation af integers i mit
filsystem, da filsystemet skal have fast længde så jeg kan bruge seekp() og
seekg().

Jeg svarer på løsningsmulighederne fra dig og Mogens i et senere brev, for
jeg kører på den 13. time og 4. kande kaffe nu.

Tak for hjælpen.

mvh. jesper






Mogens Hansen (15-05-2001)
Kommentar
Fra : Mogens Hansen


Dato : 15-05-01 23:40

Hej Jesper,
"Jesper Gødvad" <Xesper@goedvad.dk> wrote in message
news:9ds87o$i8f$1@sunsite.dk...
>
> "Igor V. Rafienko" <igorr@ifi.uio.no> wrote in message
> news:xjvheymigzw.fsf@gjallarbru.ifi.uio.no...
> > * Jesper Gødvad
> >
> > > std::string tal = "123456" // et eller andet tal
> > > Tallet skal konverteres til en long - det kan jeg godt finde udaf,
> > jøss, folk har begynt å lære (det er ikke vondt ment).
>
> Ja, men det ville være rart hvis der var en nemmere måde
>

Det er Bjarne Stroustrups intention, at der kommer en nemmere måde i næste
udgave af C++ standarden.
Det skal gøres lettere at lære C++ - dette er eet af punkterne.

Venlig hilsen

Mogens Hansen



Jesper Gødvad (18-05-2001)
Kommentar
Fra : Jesper Gødvad


Dato : 18-05-01 00:15


> > > > Tallet skal konverteres til en long - det kan jeg godt finde udaf,
> > > jøss, folk har begynt å lære (det er ikke vondt ment).
> >
> > Ja, men det ville være rart hvis der var en nemmere måde
>
> Det er Bjarne Stroustrups intention, at der kommer en nemmere måde i næste
> udgave af C++ standarden.
> Det skal gøres lettere at lære C++ - dette er eet af punkterne.

Yep. Jeg har set det ene interview hvor han taler om hvad der skal til i
fremtiden. Det ser spændende ud, men lige nu synes jeg der er rigeligt i
forvejen.

Du har tidligere henvist til bogen "C++ the Programming Language" (3rd
edition?) af Bjarne Stoustrup. Er det BOGEN der fortæller hvad der er C++ og
dermed hvad der ikke er det?

mvh. ~jesper





Mogens Hansen (18-05-2001)
Kommentar
Fra : Mogens Hansen


Dato : 18-05-01 05:13

Hej Jesper,
"Jesper Gødvad" <Xesper@goedvad.dk> wrote in message
news:9e1lqo$kn5$1@sunsite.dk...
> > Det er Bjarne Stroustrups intention, at der kommer en nemmere måde i
næste
> > udgave af C++ standarden.
> > Det skal gøres lettere at lære C++ - dette er eet af punkterne.
>
> Yep. Jeg har set det ene interview hvor han taler om hvad der skal til i
> fremtiden. Det ser spændende ud, men lige nu synes jeg der er rigeligt i
> forvejen.

Det kan jeg godt forstå - og der er formodentlig en del år til næste
standard.

>
> Du har tidligere henvist til bogen "C++ the Programming Language" (3rd
> edition?) af Bjarne Stoustrup. Er det BOGEN der fortæller hvad der er C++
og
> dermed hvad der ikke er det?
>

Ja, det er BOGEN.
Men den er stor (over 1000 sider) og omfattende (nødvendigvis).
Vær sikker på at du får en, der er trykt efter foråret 2000. Den kendes ved
at have 2 ekstra appendixes:
D. Locals
E. Standard Library Exception Safety
Den findes også i en "Special Edition" som indholdsmæssigt er identisk med
"3rd Edition", men som er trykt på bedre papir og er hårdt indbundet.
Der findes en bog (C++ Solutions: Companion to the C++ Programming Language)
med udvalgte løsninger til opgaverne, skrevet af Daveed Vandervoorde (en yng
fyr, der er med til at lave EDG compiler front-enden, og før det på HP's C++
compiler team). Se http://cseng.aw.com/book/0,3828,0201309653,00.html

Venlig hilsen

Mogens Hansen



Morten Nørgaard (16-05-2001)
Kommentar
Fra : Morten Nørgaard


Dato : 16-05-01 07:45


> Ak, jeg sidder og programmerer et distribueret database system fra
grunden.
> Det er en opgave på datamatikeruddannelsen, som jeg kan se jeg ikke er den
> eneste der kæmper med udfra andre spørgemål i denne newsgroup.Det bliver
en
> længere forklaring, men du er jo selv ude om det.

Hej Jesper,

ja, du er ikke den eneste, det er en udfordring! Held lykke med det og
lav ikke det hele selv når du har en gruppe til at backe dig up,

Morten.




Jesper Gødvad (18-05-2001)
Kommentar
Fra : Jesper Gødvad


Dato : 18-05-01 00:18


> > Det er en opgave på datamatikeruddannelsen, som jeg kan se jeg ikke er
den
> > eneste der kæmper med

> ja, du er ikke den eneste, det er en udfordring! Held lykke med det og
> lav ikke det hele selv når du har en gruppe til at backe dig up,

De sidder og finder udaf hvordan connections og tråde virker, så det er da
godt man kan sende aben videre (indtil videre).

-jesper



Mogens Hansen (15-05-2001)
Kommentar
Fra : Mogens Hansen


Dato : 15-05-01 19:53

Hej Jesper,
"Jesper Gødvad" <Xesper@goedvad.dk> wrote in message
news:9drqh2$hak$1@sunsite.dk...
> Hejsa
>
> Er der en venlig person der kan hjælpe mig med følgende konvertering:
>
> Jeg har et tal der er repræsenteret som tekst, fx:
>
> std::string tal = "123456" // et eller andet tal
>
> Tallet skal konverteres til en long - det kan jeg godt finde udaf, men jeg
> skal ikke bruge long værdien til noget.
> I stedet har jeg brug for en ny streng der er 4 chars lang og
repræsenterer
> værdien. Altså en long gemt som en char[4].

Du har jo et problem, hvis du vil representere et til, der er større end
9999 som ASCII på 4 tegn.
Hvis sizeof(long) er 4 - hvilket ikke er garanteret - så kan du bruge
"memcpy".
Det er ikke pænt. Det er ikke noget man ofte har brug for.
Jeg vil ikke opfordre til at man gør den slags, medmindre man har en _god_
grund - void pointere er potentielt farlige.
Men det er velspecificeret at det virker.

#include <string>
#include <sstream>
#include <cstring>

using std::string;
using std::istringstream;
using std::memcpy;

int main(int argc, char* argv[])
{
string number("123456");
istringstream is(number);
long value;
is >> value;
char buffer[4]; // preferable buffer[sizeof(value)];
memcpy(buffer, &value, sizeof(buffer));

return 0;
}



Venlig hilsen

Mogens Hansen



Jesper Gødvad (19-05-2001)
Kommentar
Fra : Jesper Gødvad


Dato : 19-05-01 17:33


"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:9drts4$es$1@news.cybercity.dk...

>> [Konvertering af std::string="123456" til char[4] ]

> Hvis sizeof(long) er 4 - hvilket ikke er garanteret - så kan du bruge
> "memcpy".

Men jeg kan godt gå udfra at long i praksis er 32 bit, ikke? Jeg kunne
forestille mig, at grunden til at bruge en long netop var at "forvente" en
32 bit heltals variabel.

> Det er ikke pænt. Det er ikke noget man ofte har brug for.
> Jeg vil ikke opfordre til at man gør den slags, medmindre man har en _god_
> grund - void pointere er potentielt farlige.

Nej, og nu har jeg fundet en grund til lade være. Tallene forbliver i
std::string format og konverteres til int når det er nødvendigt. Så kan jeg
også håndtere negative tal og potientielt floating-point etc.

Eneste ulempe er at datastørrelsen i min fil og ved transmission over
netværk går fra altid 4 bytes (hex format) til mellem 2- og 11 bytes (
#lænde værdi ).


> #include <string>
> #include <sstream>
> #include <cstring>

Problemet med denne er også, at jeg skal include sstream og cstring kun for
at konvertere.

Men tak for hjælpen også til SuneF.

mvh. jesper



Kent Friis (19-05-2001)
Kommentar
Fra : Kent Friis


Dato : 19-05-01 17:49

Den Sat, 19 May 2001 18:33:28 +0200 skrev Jesper Gødvad:
>
>"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
>news:9drts4$es$1@news.cybercity.dk...
>
>>> [Konvertering af std::string="123456" til char[4] ]
>
>> Hvis sizeof(long) er 4 - hvilket ikke er garanteret - så kan du bruge
>> "memcpy".
>
>Men jeg kan godt gå udfra at long i praksis er 32 bit, ikke? Jeg kunne
>forestille mig, at grunden til at bruge en long netop var at "forvente" en
>32 bit heltals variabel.

På mange 64-bit maskiner er long SVJV 64 bit.

Mvh
Kent
--
http://www.celebrityshine.com/~kfr/ - nu med Elgo-billeder

SuneF (16-05-2001)
Kommentar
Fra : SuneF


Dato : 16-05-01 13:25

> Er der en venlig person der kan hjælpe mig med følgende konvertering:

Jeg vil da gerne gøre et forsøg, har nemlig selv rodet med det i går ;)


> I stedet har jeg brug for en ny streng der er 4 chars lang og repræsenterer
> værdien. Altså en long gemt som en char[4].

gør følgende:

long tallet;
char buffer[4];

buffer[0]=(char)(tallet>>24);
buffer[1]=(char)(tallet>>16);
buffer[2]=(char)(tallet>>8);
buffer[3]=(char)(tallet);

Dette er den direkte binære metode,
bemærk at de mest betydende bit kommer i 0'te element
og de mindst betydende i 4 element.


Søg
Reklame
Statistik
Spørgsmål : 177501
Tips : 31968
Nyheder : 719565
Indlæg : 6408522
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste