En struct i C som jag inte riktigt förstår

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Henrik
Inlägg: 661
Blev medlem: 26 maj 2003, 23:39:14
Ort: Göteborg
Kontakt:

En struct i C som jag inte riktigt förstår

Inlägg av Henrik »

Denna variant föreslås av B Knudsen till hans cc5x/cc8e. Koden blir jättebra, men jag stör mig på att jag inte förstår hur den funkar. Nån som orkar förklara? Jag programmerar pic18f med cc8e.

Kod: Markera allt

const char str[] = "String 1";

const struct  {
  const char *s;
} tb[] = {
  "A table of pointer to strings",
  "Monday", "Tuesday", "W...

};
och sen för att plocka ut ett element:

Kod: Markera allt

p = tb[i].s; // const char *p; char i;
t = p[x]; // char x;
Användarvisningsbild
AndLi
Inlägg: 18274
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Inlägg av AndLi »

Kod: Markera allt

const struct  { 
  const char *s; 
} datastruct;

datastruct tb[] = { 
  "A table of pointer to strings", 
  "Monday", "Tuesday", "W... 

}; 
Är kanske enklare att förstå,

Kod: Markera allt

char namn[][] = {"kalle","oskar","nisseeeee"};
Hade ju varit sättet man velat göra det på, men du kan inte ha två okända storlekar på arrayen!

Altså får man använda en struct för att fejka till det...

Structen är första dimensionen i arrayen.

Jag vet inte riktigt om det förklarade nått eller bara rörde till det ännu mer...
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

const char str[] = "String 1"; // Är ju enkel så den struntar jag i

const struct
{
const char *s;
} tb[] = {"A table of pointer to strings",
"Monday",
"Tuesday",
"W..."};

Betyder helt enkelt:
tb[] är en tabell över char pekare. De olika strängar sparas i minnet som konstanter och i tb[] läggs deras adressor in som pekare. Om man sedan refererar till tb[?].s som underelement är den en char * vilket betyder sträng.

Det hade gått precis lika bra att ange den som:
const char * tb[] = {"A table of pointer to strings",
"Monday",
"Tuesday",
"W..."};

och sedan plocka ut som tb[?]. Men av någon anledning (kan vara casting-grej) väljer den programmör att lägga till en underpost eller också vill han att strängar ska ha namnet som är .s, vem vet?
Användarvisningsbild
Henrik
Inlägg: 661
Blev medlem: 26 maj 2003, 23:39:14
Ort: Göteborg
Kontakt:

Inlägg av Henrik »

Tack!! Precis så här man önskar sig ett svar.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Jag har oxå en fråga angående en strukt.

jag har byggt en

near struct {
unsigned A:2;
unsigned B:3;
unsigned C:3;
} UEIRbits;

Där A representerar de första 2 bittarna, B nästa 3 bitar och C de sissta 3 bitarna av ett 8 bitars tal (char)

Hur gör jag nu för att få strukten att lägga sig på adress 0x0F81 som motsvarar portB?

Går det att ha ytterligare en variabel som heter portb på samma adress utan att det sker krockar om man använder båda variablerna samtidigt (direkt efter varandra)?
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Hur du lägger den på en viss adress beror på vilken kompiler du använder, läs helpfilen

Om portb har en viss adress kan en annan pekare fint ha samma adress så om vi låtsas att man kan lokalisera med kommandot "@ 0x0F81" kan du skriva:

near struct {
unsigned A:2;
unsigned B:3;
unsigned C:3;
} UEIRbits@ 0x0F81;

I "vanlig" C kan man "overlay"a fler variabler på detta sätt:
union struct
{
unsigned long Big_One;
unsigned int As_Word[2];
unsigned char As_Byte[4];
struct
{
unsigned long B00 : 1;
unsigned long B01 : 1;
unsigned long B02 : 1;
unsigned long B03 : 1;
unsigned long B04 : 1;
unsigned long B05 : 1;
unsigned long B06 : 1;
unsigned long B07 : 1;
unsigned long B08 : 1;
unsigned long B09 : 1;
unsigned long B10 : 1;
unsigned long B11 : 1;
unsigned long B12 : 1;
unsigned long B13 : 1;
unsigned long B14 : 1;
unsigned long B15 : 1;
unsigned long B16 : 1;
unsigned long B17 : 1;
// osv.
} Bits;
} Total;

Då är Total en stor enhet men den kan kommas åt i unsigned long, words, bytes och bits på följande sätt:
Total.Big_One är unsigned Long
Total.As_Word[0...1] är som word
Total.As_Byte[0...3] är som byte
Total.Bits.B00 är som bit
Total.Bits.B01
Total.Bits.B02
osv.

Sen kollar man hur kompilern begär att man skriver lokeringen och sen kan du komma åt bits och bytes bäst du vill. Ett tips är att kolla de filer som inkluderas i systemet, speciellt de processor specifika .H-filer, där brukar portar och dylikt vara definierat med adressor på rätt sätt, kopiera detta sätt.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Tackar för förklaringen.

Jag har tittat i headerfilen, det är därifrån jag fått min strukt. Problemet är att i min headerfil (som jag fått från mplab C18) så finns inte en enda adress definierad i headerfilen. jag har letat vart adresserna tilldelas, men har inte htitat det.

Jag har hittat på nätet efter hur man lägger variabler på speciella adresser, men har inte hittat hur man gör det med strukter.
Det exemplet jag hittade använde en define sats som motsvarar en adress, vilket gör att det inte fungerar att byta ut variabeln mot en strukt.

Hur man lägger strukter på speciella adresser är väl inte specifikt för kompilatorn eller har jag fel?

Vet någon nått ord eller liknande jag skulle kunna söka på för att hitta vad jag söker?
henkebenke
Inlägg: 515
Blev medlem: 31 maj 2003, 10:42:37
Ort: Helsingborg

Inlägg av henkebenke »

dangraf skrev:Jag har oxå en fråga angående en strukt.
Hur gör jag nu för att få strukten att lägga sig på adress 0x0F81 som motsvarar portB?
Jag är tveksam på att minnesmappningen är definierad i det fallet. En strukt kan tex. mycket väl ta mer plats i anspråk än de ingående variablerna.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jo, ska man lägga en variabel i en specifik adress är det just kompiler-specifikt hur man gör, det är nämlig ingen C-grej att göra så.

Edit: Om en struct placeras över ett mindre minnesarea kommer det ju i alla fall att vara så att den största "area" bestämmer men man ställer ju enbart startadressen hursomhelst så börjar man med hårdvaruspecifika saker ska man vara "säker på handen"!

Mer edit: Om du inte hittar någon specifik definition inkluderas det nog ytterligare en fil som du ska leta i. Jag hade sökt i alle filer under det bibliotek efter någon fil som innehåller "F81", med lite klurande skulle det inte ta många minuter att hitta rätt fil och definition.
sprawl
Inlägg: 299
Blev medlem: 9 juni 2004, 13:01:33
Ort: Göteborg

Inlägg av sprawl »

Nu har jag inte kodat C på rätt länge men borde man inte kunna skriva något liknande?

Kod: Markera allt

typedef struct _UEIRbits {
        unsigned A:2;
        unsigned B:3;
        unsigned C:3;
} UEIRbits;


int main(void)
{
        UEIRbits *myBits = (UEIRbits*)0x0F81;
        myBits->A = 1;
        return 0;
}
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

jag har letat, och det närmsta jag kommit är att jag hitat portb i en *.lib fil. Men när jag öppnar den i notepad, så blir det bara en massa konstiga tecken och krumelurer tillsammans med text.
kan man läsa ut nått ur en lib fil och vilket prog ska man använda sig av då?
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Det står lite i C18 user guide, 2.11

Det verkar ganska jobbigt att göra på det sättet...

Det borde väl också funka att bara definiera din struct (som en datatyp alltså) och casta den redan definierade PORTB till den typen. Ungefär som sprawl skriver alltså, fast utan pointers eller hårdkodad adress.

Kod: Markera allt

typedef struct _UEIRbits {
        unsigned A:2;
        unsigned B:3;
        unsigned C:3;
} UEIRbits;


int main(void)
{
        ((UEIRbits)PORTB).A = 1;
        return 0;
} 
Inte testat det, men....
sprawl
Inlägg: 299
Blev medlem: 9 juni 2004, 13:01:33
Ort: Göteborg

Inlägg av sprawl »

Tror inte att cyrs variant fungerar med tanke på att PORTB förmodligen bara är en konstant med ett värde i.

dock kan man byta ut 0x0F81 mot PORTB i mitt exempel, eller definera den som en global.
Jag har inte heller testat koden så jag vet inte om den fungerar ;)

Kod: Markera allt

typedef struct _UEIRbits {
        unsigned A:2;
        unsigned B:3;
        unsigned C:3;
} UEIRbits;

UEIRbits *gPORTBBits = (UEIRbits*)PORTB;

int main(void)
{
        gPORTBBits->A = 1;
        return 0;
} 
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Tackar för alla svar!
Det verkar som att man får göra nån form av minnesmapping om man skall ha det som jag vill.

Jag kör nog på sprawl's exempel eller så lägger jag till en strukt i headerfilen så att jag får skriva PORTBbits.A ung som icecap beskrev.

extern volatile near union {
struct {
unsigned RB0:1;
unsigned RB1:1;
unsigned RB2:1;
unsigned RB3:1;
unsigned RB4:1;
unsigned RB5:1;
unsigned RB6:1;
unsigned RB7:1;
};
struct {
unsigned INT0:1;
unsigned INT1:1;
unsigned INT2:1;
};
struct {
unsigned :5;
unsigned PGM:1;
unsigned PGC:1;
unsigned PGD:1;
};
sttruct{
unsigned A:2;
unsigned B:3;
unsigned C:3;
}

} PORTBbits;


tack igen!
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

sprawl skrev:Tror inte att cyrs variant fungerar med tanke på att PORTB förmodligen bara är en konstant med ett värde i.
PORTB är faktiskt definierad i header-filen som en:

extern volatile near unsigned char

(phew!).
Skriv svar