Sida 1 av 2

Korrekt enligt C-standard?

Postat: 28 maj 2014, 21:53:39
av arte
Hej,

Jag undrar ifall denna kod snutten bryter mod C-standarden på något sätt:

Kod: Markera allt

static short FSHORT(short x)
{
  return (((unsigned char *) &x)[1]<< 8) +
          ((unsigned char *) &x)[0];
}

void main()
{
	printf("Val %d \n",FSHORT(1));
}
Den fungar på en arch men inte en annan. Ifall x hamnar på stacken så fungerar det men ifall det hamnar i ett register så blir det så klart knas.
Inga vidare bra kod men nyfiken på vad C standarden säger.

Någon som vet?

Re: Korrekt enligt C-standard?

Postat: 28 maj 2014, 22:52:56
av johano
Koden förutsätter att storleken på unsigned char är mindre än storleken på short vilket inte nödvändigtvis är fallet...det finns system där sizeof(char)==sizeof(short)

/johan

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 00:21:29
av blueint
Helt otestat:

Kod: Markera allt

static short FSHORT(short x)
{
  return (
(* (((unsigned char *) &x)+1) )<< 8) |
(* (((unsigned char *) &x)+0) )<<0)  );
}
Kanske fungerar bättre? eller någon variation därav.

Ta dock en rejäl kik på vad sizeof(short) och sizeof(char) ger.

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 00:29:48
av arte
Fast det stora problemet är väl att ta addressen av ett argument.
Altså:

Kod: Markera allt

void func(int r0)
{
    int *ptr = &r0;

    return *ptr;
}
I koden ovan kommer ptr inte kunna peka till något vettigt?
Ifall variablen r0 är sparad i ett register så blir det inge bra.

Jag söker inte efter en lösning utan bara nyfiken på hur C fungerar.
(lösningen på problemet är att spara r0 i en lokal variabel innan man referar till det)

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 00:31:38
av blueint
Testat att det fungerar:

Kod: Markera allt

static short FSHORT1(short x)
{
return
      (*(((unsigned char *)&x)+1)<<8) |
      (*(((unsigned char *)&x)+0)<<0);
}
Kombinera gärna med denna huvudfunktion:

Kod: Markera allt

int main()
{
  printf("short=%u  char=%u\n",sizeof(short), sizeof(char) );
  printf("Val 0x%04X\n",FSHORT1(0x1234));

return 0;
}
Anledningen till att jag blev lite fundersam på din funktion var att den innehöll en referens till "short x" som en array när det är en address som använts.

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 00:51:48
av bearing
Huruvida argument sparas i register eller RAM har med "calling conventions" på den aktuella architekturen att göra.

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 01:39:58
av blueint
Vilka arkitekturer rör det sig om?

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 09:38:19
av Icecap
Det kan fungera OK men det beror på endian för systemet. Det bör fungera för little endian men för big endian blir det fel.

Sedan kan det komma problem med register osv. beroende på målsystem, t.ex. PIC har ju ingen stack som sådan att överföra värden i varför register kan bli inblandat.

Men jag skulle definitivt kolla på endian innan jag gick vidare.

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 10:24:18
av johano
Det är naturligtvis helt legalt i C att ta adressen av en funktionsparameter, det är kompilatorns jobb att se till att den hamnar rätt om den nu skickades via ett register.

Om detta inte funkar i ditt fall så är det en bugg i kompilatorn.

Vad är det för plattform/kompilator?

/johan

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 12:44:24
av sodjan
Detta kanske kan flyttas till "Programmering"?
Jag ser ingen referens till något specifik plattform eller hårdvara.

> Den fungar på en arch men inte en annan.

Vad betyder "fungerar"? Vad förväntas och vad är skillnaden mellan olika "arch"?

> Ifall x hamnar på stacken så fungerar det men ifall det hamnar i ett register så blir det så klart knas.

Vad betyder "knas" mer specifikt? Crasch? Skräpvärden?

Själv får jag bara samma värde ut från fprint som in till FSHORT().
Om det är förväntat så fungerar det oavsett hur jag skruvar på
optimeringen.

Hela FSHORT() kör mot register och blir 6 maskininstruktiner (inkl RETURN).

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 14:16:56
av mri
Skall du göra det där korrekt måste du gå via en union.

Jag har själv spenderat många timmar på att leta efter en bugg som kom utav ditt förslag att typkonvertera genom en pekare. Den buggiga koden var skriven för visual c kompilatorn var allt funkade okay. Med gcc och ganska aggressiv optimering blev det fel i vissa fall eftersom kompilatorn ändrade ordningsföljden.

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 15:07:44
av sodjan
Vad är det korrekta "svaret"?
Med FSHORT(1234) skriver fprint() ut "Val 1234".

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 15:21:53
av mri

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 17:32:36
av arte
johano skrev:Det är naturligtvis helt legalt i C att ta adressen av en funktionsparameter, det är kompilatorns jobb att se till att den hamnar rätt om den nu skickades via ett register.

Om detta inte funkar i ditt fall så är det en bugg i kompilatorn.

Vad är det för plattform/kompilator?
/johan
Lite detta jag fiskade efter!

Det är GCC och platformen är ZPU (en OpenSource processor).
Kan mycket väl vara buggar i den kompilatorn.

Så det är fullt legalt att göra så?
blueint skrev:Vilka arkitekturer rör det sig om?
Fungerar på ARMv7, x86 fungerar inte på ZPU.
Men som johan säger så skall det fungera på alla arch.

Re: Korrekt enligt C-standard?

Postat: 29 maj 2014, 17:50:02
av sodjan
Jag har fortfarande inte förstått vad "fungerar" betyder här.
Exakt vilket resultat förväntas? Eller betyder "fungerar"
bara att det går att kompilera?