Ting jeg savner i C

C sproget fik på et tidspunkt de mest ubrugelige enum's jeg kender i noget programmeringssprog og resultatet er at kun meget ideologiske programmører bruger dem overhovedet.

Her er et lille aktuelt eksempel hvor de kunne have været brugbare, hvis bare nogen havde tænkt sig om.

Jeg sidder med en microcontroller der skal tale MODBUS og har derfor en array med navngivne indices.

I kildeteksten ser det således ud:

static uint16_t hold[9]; #define HOLD_TEMPI 0 #define HOLD_TEMPIX 1 #define HOLD_TEMPO 2 #define HOLD_TEMPOX 3 #define HOLD_PWM 4 #define HOLD_RPM 5 #define HOLD_VCC 6 #define HOLD_VCORE 7 #define HOLD_VREF 8

Er det egentlig ikke til at tude over ?

Tænk hvis enum's havde været lavet fornuftigt, så kunne man f.eks have skrevet:

enum hold_vars {     TEMPI, TEMPIX, TEMPO, TEMPOX,     PWM, RPM, VCC, VCORE, VREF }; static uint16_t hold[enum hold_vars];

Jeg vil vædde på at ovenstående er en temmelig triviel ting at implementere i en C-compiler, det kan næppe tage mere end 30 linier kode...

phk

Kommentarer (27)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
#1 Thomas Ammitzbøll-Bach

Et hack, der smager af fisk:

[code=c] enum hold_vars { TEMPI, TEMPIX, TEMPO, TEMPOX, PWM, RPM, VCC, VCORE, VREF, _HOLD_SZ }; static uint16_t hold[_HOLD_SZ]; [/code]

Det største problem er den svage scoping og typing. Jeg ville forvente, at enum identifiers kun kunne bruges med variable, der er erklæret af den pågældende enum type (eller arrays, med indeks af den pågældende enum type).

Det er ikke vanskeligt at implementere, det koster ikke noget i køretid, og man kan altid typecast'e sig ud af konverteringer.

Thomas

  • 0
  • 0
#2 Kim Schulz

På min arbejdsplads hvor stort set alt kodes i C er enums simpelthen forbudt at bruge. Det giver nogle gange noget ganske grimt kode, men til gengæld er den porterbar til alle de platforme vi arbejder med. Fatter ikke hvorfor de ikke bare fik sat en størrelse på enums elementer fra start af, så vi kunne komme ud over alt det pjat.

  • 0
  • 0
#3 Hans Schou

Hvorfor ikke en struct?

[code=c]static struct { uint16_t TEMPI; uint16_t TEMPIX; uint16_t TEMPO; uint16_t TEMPOX; uint16_t PWM; uint16_t RPM; uint16_t VCC; uint16_t VCORE; uint16_t VREF; } hold; [/code]

Og en [code=c]union[/code] uden om hvis et array skulle være nødvendigt.

  • 0
  • 0
#4 Lasse Reinholt

Det kan være en fordel at bruge variabler i stedet, i de tilfælde hvor det er muligt: const int HOLD_TEMPI = 0; const int HOLD_TEMPIX = 1; ... Det giver type checking og desuden kan deres værdier udlæses under debugging, hvilket #defines ikke kan. Hastigheds/størrelsesmæssigt giver det samme resultat undtagen i specialtilfælde. Preprocessor ting bør man i det hele taget kun bruge, hvor der ikke findes et alternativ, som er lige så godt.

  • 0
  • 0
#5 Jesper Louis Andersen

I Go har de en noget underlig iota-konstruktion. iota resettes hver gang man støder på en const og inkrementeres så hver gang man anvender den. Den kan endda udelades:

const (  
  HOLD_TEMPI = iota  
  HOLD_TEMPIX  
  HOLD_TEMPO  
  HOLD_PWM  
  HOLD_RPM  
  ...  
)

Til gengæld ser det ikke ud til at de har lyttet til PHK for sproget lader dig ikke erklære et array i antallet af elementer som er erklæret i en const-block så vidt jeg kan se.

Til gengæld kunne jeg godt tænke mig at vide hvorfor man har et behov for det array, for der kunne være en anden måde at beskrive problemet på som er bedre.

  • 0
  • 0
#6 Robert Larsen

Hvad er enums egentlig til for ?

Når dette er tilladt:

enum test {  
    FIRST = 7,  
    SECOND = 7  
};

...og dette er muligt:

enum test {  
    FIRST = 0,  
    SECOND = 1  
};  
   
void do_stuff(enum test) {  
}  
   
int main (int argc, char ** argv) {  
    do_stuff(18);  
    return 0;  
}

...og dette ikke giver antallet af enum værdier:

#include <stdio.h>  
   
enum test {  
    FIRST = 0,  
    SECOND = 1  
};  
   
int main (int argc, char ** argv) {  
    printf("%d\n", sizeof(enum test));  
    return 0;  
}

...så forstår jeg ikke længere, hvad jeg skal bruge enum til.

Javas version af enum giver mening (synes jeg), men C's giver en falsk tryghed (synes jeg).

  • 0
  • 0
#7 Poul-Henning Kamp Blogger

Jeg bruger ikke en struct fordi MODBUS datamodellen er en array af 16 bit ints.

Ideen med at overlejre en union vil jeg slet ikke kommentere, det er hverken sikkert, kønt eller portabelt.

Poul-Henning

  • 0
  • 0
#10 Jon Loldrup

Hvad med Google Go - mon ikke det har gode chancer for at overtage C's rolle som foretrukkent sprog til ressourceknappe platforme? (f.eks. 8-bit sager) Det ville jeg sætte pris på.

  • 0
  • 0
#12 Thomas Ammitzbøll-Bach

Nu er der jo tale om hardwarenært programmering, så jeg er lidt nysgerrig i forhold til Java her:

Hvordan angiver man absolutte adresser i Java? Hvordan skifter man endianess i Java? Hvordan mikser man assembler med Java? Hvordan laver man interuptrutiner i Java?

Jeg har skrevet en del linier C på platforme, hvor der ikke er noget runtime system (f.eks. operativsystem), og jeg kan ikke rigtig få det til at gå op med den abstraktion, som Java giver. Men jeg kender ikke nok til Java på det felt.

Please enlighten me here

Thomas

  • 0
  • 0
#13 Per Steffensen

Rart at blive betragtet som nuttet :-)

Bare lige for at slå det fast, så nævnte jeg ikke noget om java. Når det så er sagt, så er der ikke noget i sproget java, som gør at det ikke lige så godt kunne compileres ned og køre på "resourceknappe platforme". Java kunne såmænd godt kompileres "ned til jernet" i stedet for at blive kompileret til "hardward-neutral" java-bytekode, hvis man vil undgå den "store tunge" JVM.

Heldigvis findes der andre sprog end Java og C.

  • 0
  • 0
#15 Christian Nobel

men man kører nu engang ikke Java på en 8-bit microcontroller...

Man "kører" vel heller ikke C på en microcontroller, men man udvikler muligvis i C, for efterfølgende at kompilere til brug på mikrokontolleren.

Det skulle jo gerne fylde så lidt som muligt, men egentlig kunne man vel bruge et hvilket som helst anvendeligt programmeringssprog der kan kompilere til den givne processor - eller man kan jo være hardcore og skrive direkte i assembler.

Herudover forstår jeg slet ikke alt hypen omkring C og alle dets varianter.

/Christian

  • 0
  • 0
#16 Per Steffensen

Der er ikke (længere) nogen "hype" omkring C. Det er en defacto-standard i visse områder af branchen, som en masse udviklere derfor (uden nogen god grund, og heriblandt øjensyneligt Poul-Henning) må lide under. Mange af dem ved heldigvis ikke selv at de lider :-)

  • 0
  • 0
#17 Lars Clausen

Jeg vil holde med PHK, Java er et teenagersprog, hvor man ikke har nogen som helst kontrol over hvad der virkelig sker i de mange modificerede og udokumenterede objekter. Men nu må i også godt kalde mig for en programmerings dinosaur :-D Der synes det eneste 'Bare Metal' sprog er assembler, og C er højniveau ;-)

Jeg bruger selv Codevision C til AVR controllere (Altså ikke PHK's AVR GCC / GNU compiler).

Codevision fungerer absolut strålende! (Men koster 150 Euro).

Korrekt kode er: (Iflg dokumentationen:)

enum months {january, february, march, april, may, june, july, august, september, october, november, december} months_of_the_year;

Var det ikke det du efterlyste PHK ?

  • 0
  • 0
#18 Lars Clausen

Ups jeg overså lige at det muligvis ikke var AVR controllere der var tale om. Variablen Vcore kunne pege på en version af ARM.

Men et opslag i Kernighan and Ritchie (1988) som jeg selvfølgelig har stående i bogreolen .. :-S viser at den korrekte syntax for enum er:

enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};

Så meget tæt op af PHK's eget forslag til hvordan det burde være løst. Eettallet ved JAN er for at give den første værdi 1, ellers bliver den defaulted til 0.

  • 0
  • 0
#20 Baldur Norddahl

Nu er der jo tale om hardwarenært programmering, så jeg er lidt nysgerrig i forhold til Java her:

Hvordan angiver man absolutte adresser i Java? Hvordan skifter man endianess i Java? Hvordan mikser man assembler med Java? Hvordan laver man interuptrutiner i Java?

Disclaimer: Jeg forslår ikke at java er det rigtige valg til systemprogrammering. Formålet med dette indlæg er blot at pointere at man godt kan, hvis man vil.

1) absolutte adresse kan angives i en integer. Hukommelse kan projekteres via et array. Arrayet kan oprettes via JNI kald.

2) Det gør man ikke, ligesom der ikke findes nogen måde i C. Det er en opgave for oversætteren.

3) Man bruger JNI.

4) På samme måde som i C. Bemærk at hverken C eller Java har nogen sprogegenskab som er specielt rettet mod at skrive interruptrutiner. Det er op til oversætteren og eksekveringsmiljøet om det smertefrit lader sig gøre.

  • 0
  • 0
#21 Michael Rasmussen

Bemærk at hverken C eller Java har nogen sprogegenskab som er specielt rettet mod at skrive interruptrutiner

man sigaction -> "The sigaction() system call is used to change the action taken by a process on receipt of a specific signal."

  • 0
  • 0
#22 Baldur Norddahl

man sigaction -> "The sigaction() system call is used to change the action taken by a process on receipt of a specific signal."

Det står ellers meget tydeligt i det du citerer: sigaction er et systemkald, og ikke en del af sproget C. Det er f.eks. ikke tilgængeligt på mange platforme som ellers godt kan køre C programmer.

Du falder i standard fælden med at blande OS kald sammen med sproget.

På en mikrokontroller uden OS er der ikke noget sigaction kald - med mindre du skriver det selv i assembler. Og da kan du ligeså godt skrive sigaction på en måde, så den kan finde ud af at kalde en java metode, eller en metode i et vilkårligt andet sprog.

  • 0
  • 0
#24 Michael Rasmussen

Du falder i standard fælden med at blande OS kald sammen med sproget.

At jeg nævnte sigaction, har følgende grund: "[..]Avoid its use: use sigaction(2) instead"

Siden C89 har sproget haft signals, men på de fleste, POSIX kompatible, platforme anbefales det at anvende sigaction. "signal - ANSI C signal handling" "CONFORMING TO C89, C99, POSIX.1-2001."

  • 0
  • 0
#25 Baldur Norddahl

Siden C89 har sproget haft signals

Du mener at standard C biblioteket har haft signals. Det er mig bekendt ikke et reserveret keyword i sproget C. Det er en del af eksekveringsmiljøet, som ofte ikke er fuldt tilgængeligt. Normalt kalder man det vist stadig for C, selv når platformen ikke implementere hele standard C lib.

En java compiler til en mikrokontroller vil naturligvis komme med en tilsvarende funktion. Det er dog ikke en del af standard java biblioteket, for java er ikke tænkt til det brug.

Det var ikke min mening at vi skulle ud i et langt skænderi om hvad der ligger i diverse biblioteker. Mit budskab er simpelt at i selve sproget er der som sådan ikke den store forskel.

  • 0
  • 0
#26 Mark Ruvald Pedersen

Jeg efterlyser at min array bliver dimensioneret så den kan indexeres af alle definerede elementer i enum'en.

Tja, følgende virker i hvertfald under gcc:

enum hold_vars { TEMPI, TEMPIX, TEMPO, TEMPOX, PWM, RPM, VCC, VCORE, VREF, __LAST /* !!! Keep this as last enum at all times !!! */ }; static uint16_t hold[__LAST];

Hvis jeg husker rigtigt er det altid (signed?) int's der gemmer sig bag enums. De int værdier de antager ramper op, 0-baseret - når intet andet er angivet.

Men det gælder måske ikke for din µC compiler?

  • 0
  • 0
#27 Poul-Henning Kamp Blogger

Ja, det virker, men forklar mig lige om du synes det er kønt at du skal bruge seks udråbstegn for at forklare læseren hvad det er du ikke kan forklare C-compileren ?

Min anke er ikke at man ikke kan lave et hack, min anke er at det ikke kan laves rent.

Poul-Henning

  • 0
  • 0
Log ind eller Opret konto for at kommentere