Hvordan konvertere struct til char array i C

stemmer
9

Jeg prøver å konvertere en struct til en char array å sende over nettverket. Men jeg får noen rare utgang fra røye array når jeg gjør.

#include <stdio.h>

struct x
{
   int x;
} __attribute__((packed));


int main()
{
   struct x a;
   a.x=127;
   char *b = (char *)&a;
   int i;
   for (i=0; i<4; i++)
      printf(%02x , b[i]);
   printf(\n);
   for (i=0; i<4; i++)
      printf(%d , b[i]);
   printf(\n);
   return 0;
}

Her er den effekt for forskjellige verdier av øks (på en X86 bruker gcc):
127:
7f 00 00 00
127 0 0 0

128:
ffffff80 00 00 00
-128 0 0 0

255:
ffffffff 00 00 00
-1 0 0 0

256:
00 01 00 00
0 1 0 0

Jeg forstår verdiene for 127 og 256, men hvorfor endre tallene når du går til 128? Hvorfor skulle ikke det bare være: 80 00 00 00 128 0 0 0

Er jeg glemme å gjøre noe i konverteringsprosessen eller jeg glemme noe om heltallsrepresentasjon?

* Merk: Dette er bare et lite testprogram. I et ekte program har jeg mer i struct, bedre variabelnavn, og jeg konvertere til lille-endian.
* Edit: formatering

Publisert på 11/01/2009 klokken 20:58
kilden bruker
På andre språk...                            


10 svar

stemmer
11

Det du ser er skiltet bevare konvertering fra char til int. Oppførselen Resultatene fra det faktum at på systemet ditt, er røye signert ( Merk: char er ikke signert på alle systemer). Som vil føre til negative verdier dersom en bit-mønster gir en negativ verdi for en forkulling. Fremme en char til en int vil bevare tegnet og int vil være negativt også. Merk at selv om du ikke sette en (int)eksplisitt, vil kompilatoren automatisk fremme tegnet til en int når passerer til printf. Løsningen er å konvertere verdien til unsigned charførste:

for (i=0; i<4; i++)
   printf("%02x ", (unsigned char)b[i]);

Alternativt kan du bruke unsigned char*fra starten av:

unsigned char *b = (unsigned char *)&a;

Og så trenger du ikke noen kastet på det tidspunktet du skrive den ut med printf.

Svarte 11/01/2009 kl. 21:17
kilden bruker

stemmer
8

Den xformat Specifier av seg selv sier at argumentet er en int, og siden tallet er negativt, printfkrever åtte tegn for å vise alle de fire ikke-null byte av int-sized verdi. Den 0modifier forteller til pad utgangen med nuller, og 2modifier sier at minimum produksjonen skal være to tegn. Så vidt jeg kan fortelle, printfikke gir en måte å angi en maksimal bredde, med unntak av strenger.

Nå da, er du bare passerer en char, så bare xforteller funksjonen til å bruke hele intsom ble vedtatt i stedet - på grunn av mislighold argument kampanje for " ..." parametere. Prøv hhmodifier å fortelle funksjonen til å behandle argumentet som bare en chari stedet:

printf("%02hhx", b[i]);
Svarte 11/01/2009 kl. 21:12
kilden bruker

stemmer
8

røye er en signert type; så med toerkomplement, er 0x80 -128 for et 8-bits heltall (dvs. en byte)

Svarte 11/01/2009 kl. 21:02
kilden bruker

stemmer
5

Behandle din struct som om det var en røye array er udefinert oppførsel. Å sende den over nettverket, bruke riktig serialisering stedet. Det er en smerte i C ++ og enda mer i C, men det er den eneste måten din app vil fungere uavhengig av maskinene lesing og skriving.

http://en.wikipedia.org/wiki/Serialization#C

Svarte 11/01/2009 kl. 21:07
kilden bruker

stemmer
2

Konvertering strukturen din til tegn eller byte den måten du gjør det, kommer til å føre til problemer når du prøver å gjøre det nettverket nøytral. Hvorfor ikke ta opp det problemet nå? Det finnes en rekke forskjellige teknikker du kan bruke, som alle er sannsynlig å være mer "bærbar" enn hva du prøver å gjøre. For eksempel:

  • Sender numeriske data over nettverket i en maskin nøytral måte har lenge blitt behandlet, i det POSIX / Unix verden, via funksjoner htonl, htons, ntohlog ntohs. Se for eksempel byteorder (3) manuell side på en FreeBSD eller Linux-system.
  • Konvertering av data til og fra en helt nøytral representasjon som JSON- er også helt akseptabelt. Tiden programmene bruker å konvertere data mellom JSON og innfødte former er sannsynlig å bleke i forhold til nettverk overføring ventetider.
Svarte 11/01/2009 kl. 21:41
kilden bruker

stemmer
1

Når du går å sende den, bare bruk:

(Char *) og CustomPacket

å konvertere. Fungerer for meg.

Svarte 11/04/2010 kl. 10:04
kilden bruker

stemmer
1

Den signedness av røye array er ikke roten av problemet! (Det er -A- problem, men ikke det eneste problemet.)

Justering! Det er stikkordet her. Det er derfor du aldri skal prøve å behandle structs som rå minne. Comp (og diverse optimalisering flagg), operativsystemer og månefasene alle gjør rare og spennende ting til selve plasseringen til minne om "tilstøtende" felt i en struktur. For eksempel, hvis du har en struct med en char etterfulgt av en int, vil hele struct være åtte byte i minnet - det røye, 3 blank, unyttig bytes, og deretter fire byte for int. Maskinen liker å gjøre ting som dette så structs kan passe rent på sidene til minnet, og lignende.

Ta et introduksjonskurs til maskin arkitektur på ditt lokale college. I mellomtiden, serial riktig. Aldri behandle structs som char arrays.

Svarte 26/02/2010 kl. 05:24
kilden bruker

stemmer
1

røye er en signert typen så hva du ser er det to-kompliment representasjon, støping til (unsigned char *) vil fikse det (Rowland bare slå meg).

På en side note kan du ønsker å endre

for (i=0; i<4; i++) {
//...
}

til

for (i=0; i<sizeof(x); i++) {
//...
}
Svarte 11/01/2009 kl. 21:04
kilden bruker

stemmer
0

Det kan være lurt å konvertere til en unsigned char array.

Svarte 11/01/2009 kl. 21:04
kilden bruker

stemmer
-1

Med mindre du har veldig overbevisende målinger som viser at hver oktett er dyrebar, ikke gjør dette . Bruk en lesbar ASCII-protokoll som SMTP , NNTP- , eller en av de mange andre fine Internett-protokoller kodifisert av IETF.

Hvis du virkelig må ha et binært format, er det fortsatt ikke trygt bare å skubbe ut bytes i en struct, fordi byte orden, grunnleggende størrelser, eller justering begrensninger kan avvike fra vert til vert. Du må designe din ledning protcol å bruke veldefinerte størrelser og å bruke en veldefinert byte rekkefølge. For dine gjennomføring, enten bruke makroer som ntohl(3)eller bruk skiftende og maskering for å sette byte i strømmen din. Uansett hva du gjør, sørg for at koden din produserer samme resultat på begge store endian og little-endian verter.

Svarte 13/01/2009 kl. 02:06
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more