C struct problem

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
TheUnreal
Inlägg: 115
Blev medlem: 4 september 2005, 16:04:57
Ort: Sundsvall
Kontakt:

C struct problem

Inlägg av TheUnreal »

Kanske är ett rätt grundläggande fel då jag aldrig lärt mig C "på riktigt" utan reverse enginerat från C++ :)

Jag har ett projekt för RPI Pico W, och jobbar i VS Code på windows burk.

Är ute efter att lagra konfigurationer i flash, men har blandad framgång.

Har i header-fil specat en struct:

Kod: Markera allt

struct larmSettings{
    uint32_t base;
    char mail[LARM_MAIL_MAX_LEN + 1];
    char prefix[LARM_PREFIX_MAX_LEN + 1];
    char high[LARM_HIGH_MAX_LEN + 1];
    char low[LARM_LOW_MAX_LEN +1 ];
    char suffix[LARM_SUFFIX_MAX_LEN + 1];
    char highFlank;
    char lowFlank;
};
base är det som ställer till det, mer om det efter koden :)

main.c:

Kod: Markera allt

...
#include "dhcpserver/dhcpserver.h"
struct larmSettings larm[4];

...

static const char *cgi_burn_to_flash(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]){
    for (int i = 0; i < iNumParams; i++){
        if (strcmp(pcParam[i], "burn") == 0) {
            if (strncmp(pcValue[i], "larm1", 5) == 0){
                // TODO - utred varför base enligt nedan är "1" borde vara i stil med 0x1ffe00
                printf("Larm 1 to flash! Address: %x \n", larm[0].base);
                printf("Larm 1 prefix sent: %c%c%c...\n", larm[0].prefix[0], larm[0].prefix[1], larm[0].prefix[2]);
                burnFlash (pcValue[i], (void*) &larm[0]);
            }
            ...
        }
     }
    return html[1];
}

...

int main() {
	...
	for(char i = 0; i<4; i++){
        larm[i].base = SETTINGS_BASE - (PAGE_SIZE * (i + 1));
        printf("BASE %i= %x\n", i+1,  larm[i].base);
        strncpy(larm[i].prefix, (char*)larm[i].base+XIP_BASE + LARM_PREFIX_OFFSET, LARM_PREFIX_MAX_LEN );
        ...
    }
    ...
}
Så vad jag tror att jag gör:
Vid uppstart ladda in data från flash i struct.
Det finns några sidor för att justera larminställningar i ram.
Och när man är nöjd bränna till flash (Ja man kan ju bara bränna varje bit en gång efter att den raderats med förväntat resultat, därför kan man bränna en del saker var för sig. Jag tänker mig att ni kan räkna ut att det finns funktioner för wifi och smtp med...)
Base är adressen i flash för just detta larm lagras ej i flash (det vore ju lite dumt....) utan beräknas i början av main()

Debugutskriften i main() ger:

Kod: Markera allt

BASE 1= 1ffe00
BASE 2= 1ffd00
BASE 3= 1ffc00
BASE 4= 1ffb00
vilket känns rätt, men debugutskrift för cgi_burn_to_flash är inte lika kul:

Kod: Markera allt

Larm 1 to flash! Address: 1
Larm 1 prefix sent: ban...
Men värdet i prefix är rätt.
Till historien hör att det fungerar bra att lagra data för wifi, dock upprepar sig problemet i smtp-inställningar där jag försöker lagra port i uint16_t, men ett problem i taget så löser det sig nog där med ;)

Skit oxå, det löste sig inte genom att formulera problemet...
Jag skulle kunna hårdkoda adresser men vill inte :)
Ser någon vad jag strulat till?
MiaM
Inlägg: 10092
Blev medlem: 6 maj 2009, 22:19:19

Re: C struct problem

Inlägg av MiaM »

Kör debugutskriften en gång till i loopen i main, fast i slutet, för att se om nån av de andra tilldelningarna skrivit över något.
Användarvisningsbild
AndLi
Inlägg: 17278
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: C struct problem

Inlägg av AndLi »

Hur kallar du din cgi_burn_to_flash funktion?
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45420
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: C struct problem

Inlägg av TomasL »

Vad händer om du gör en typedef i stället, typ

Kod: Markera allt

typedef struct {
    uint32_t base;
    char mail[LARM_MAIL_MAX_LEN + 1];
    char prefix[LARM_PREFIX_MAX_LEN + 1];
    char high[LARM_HIGH_MAX_LEN + 1];
    char low[LARM_LOW_MAX_LEN +1 ];
    char suffix[LARM_SUFFIX_MAX_LEN + 1];
    char highFlank;
    char lowFlank;
} struct_larmSettings;

och

Kod: Markera allt

struct_larmSettings larm[4];
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: C struct problem

Inlägg av agehall »

Att göra en typedef av struct:en gör ingen skillnad - det kan göra koden mer läsbar men gör inget åt felet.

Däremot undrar jag varför du lagrar base i en uint32_t - det borde vara en void* eller en struct larm_settings*.
TheUnreal
Inlägg: 115
Blev medlem: 4 september 2005, 16:04:57
Ort: Sundsvall
Kontakt:

Re: C struct problem

Inlägg av TheUnreal »

Tack till MiaM för knuffen som fick igång tankeverksamheten igen!

Allt såg bra ut genom hela main();
Men när jag satte in en debug utskrift i början av cgi_burn_to_flash:

Kod: Markera allt

static const char *cgi_burn_to_flash(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]){

    // DEBUG
    for (int i = 0; i < 4; i++){
        printf("BASE %i= %x\n", i+1,  larm[i].base);
    }

    for (int i = 0; i < iNumParams; i++){
        if (strcmp(pcParam[i], "burn") == 0) {
            if (strncmp(pcValue[i], "larm1", 5) == 0){
                // TODO - utred varför base enligt nedan är "1" borde vara i stil med 0x1ffe00
                printf("Larm 1 to flash! Address: %x \n", larm[0].base);
                printf("Larm 1 prefix sent: %c%c%c...\n", larm[0].prefix[0], larm[0].prefix[1], larm[0].prefix[2]);
                burnFlash (pcValue[i], (void*) &larm[0]);
            }
            ...
        }
     }
    return html[1];
}
Fick jag vid skrivning av larm 1 resultatet:

Kod: Markera allt

BASE 1= 0
BASE 2= 1ffd00
BASE 3= 1ffc00
BASE 4= 1ffb00
Och sedan för larm 3:

Kod: Markera allt

BASE 1= 0
BASE 2= 1ffd00
BASE 3= 1
BASE 4= 1ffb00
Nu vaknade hjärnan igen...
Felet fanns i

Kod: Markera allt

static const char *cgi_save_larm(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]){
Jag hade glömt att hantera base i den temporära

Kod: Markera allt

struct larmSettings temp;
. (svårhittat när man debuggar genom att söka alla ställen man gör något med "base"... :oops: )


AndLi:
Jag sparkar i main() på:

Kod: Markera allt

while(1){
        if(running){
            cyw43_arch_poll();
        }
        sleep_ms(10);
    }
Och så sker Automagiska saker i lwip


TomasL:
Jag satt några timmar innan jag skrev och försökte googla mig fram till skillnader mellan dessa två metoder, men blev ärligt talat inte slug av det och undvek då att koda sönder innan jag förstått. Det kan iofs ha att göra med tidpunkten för googlingen :)

agehall:
Bra fråga :)
Jag gör beräkningar på några ställen, ja kanske bara när jag hämtar upp datat ur flash, och med olika datatyper tyckte jag att det var lämpligt att hålla sig till integers i beräkningarna och sedan casta till rätt pointer när man läser.
*Edit: förtydligat rad ovan*
Kanske ett snedtänk?

Sammanfattning:
Jag var dum, nu fungerar just det här iaf :)

Sidenote:
Min kollega säger att alla borde ha en nalle att förklara sina problem för, frågan är hur många gånger jag behövt förklara det här innan jag själv förstått vad jag pratat om :)
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: C struct problem

Inlägg av agehall »

Om det är en pekare så ska det representeras av en pekare. Det är grundregeln och vill man bryta mot den ska man ha riktigt bra anledningar som ska stå i kommentaren bredvid. Och varje gång man gör en cast ska man tänka igenom noga varför man gör den. Oftast har man gjort något fel när man måste använda en cast.
Användarvisningsbild
Icecap
Inlägg: 26194
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: C struct problem

Inlägg av Icecap »

Om du bara visste hur många inlägg jag har skrivit med fråga om hur man löser ett givet problem - o mitt i beskrivelsen hittat problemet/googlat något som gav lösningen - o sedan raderat inlägget utan skriva klart.
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: C struct problem

Inlägg av agehall »

Hehe, ja det är ju standard. :)
MiaM
Inlägg: 10092
Blev medlem: 6 maj 2009, 22:19:19

Re: C struct problem

Inlägg av MiaM »

agehall skrev: 11 juni 2023, 15:43:04Om det är en pekare så ska det representeras av en pekare. Det är grundregeln och vill man bryta mot den ska man ha riktigt bra anledningar som ska stå i kommentaren bredvid. Och varje gång man gör en cast ska man tänka igenom noga varför man gör den. Oftast har man gjort något fel när man måste använda en cast.
Det verkar väl vara en offset inom en minnesarea. Är rekommendationen att addera två pekare med varandra för att peka ut plats inom en blob/char-array? Jag har nog cirka alltid använt ett heltal att addera på pekare (eller så kan man skriva t.ex. pekare[offset] om man tycker det är snyggare).

P.S. trots att jag hållt på med C i nån mån i minst 30 år så måste jag halvofta kolla upp syntaxen för vissa pekarrelaterade grejer när jag inte använt C på ett tag. Syntaxen för detta är inget vidare.
bearing
Inlägg: 11318
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: C struct problem

Inlägg av bearing »

Tycker också att pekaren ska vara en pekare.
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: C struct problem

Inlägg av agehall »

MiaM skrev: 11 juni 2023, 23:40:27Är rekommendationen att addera två pekare med varandra för att peka ut plats inom en blob/char-array? Jag har nog cirka alltid använt ett heltal att addera på pekare (eller så kan man skriva t.ex. pekare[offset] om man tycker det är snyggare).
Eftersom larm.base cast:as till en char* där den används i koden i första inlägget så verkar det väldigt fel att ha den som uint32_t. Om man måste cast:a data innan den används i så här pass ”enkel” kod är något fel. Här är felet att base är fel typ. Allt hänger dock på hur du skriver koden. Om du använder pekare[offset] så kan du köra med int som offset utan problem - dina intentioner är uppenbara och det kommer fungera utan cast.
Användarvisningsbild
Icecap
Inlägg: 26194
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: C struct problem

Inlägg av Icecap »

I min optik använder man uteslutande cast när man t.ex. ska plocka en signed byte till en unsigned värde. Som t.ex. där en läsning av en I2C temp-sensor ger 4 bytes i svar o 2 av dom är var sin del av ett 16-bit värde.

Dessa bytes skulle vi packa till en s_int16_t och personen som inte var så våldsamt van att programmera C hade en hel del problemer.

Vid att casta var sin byte, en i taget, o köra en MSB*256 + LSB till en s_int16_t fick vi ett användbart värde.

I det fall anser jag att det är fullt legalt att casta - men ut över detta är jag starkt tveksam.
agehall
Inlägg: 427
Blev medlem: 12 augusti 2020, 19:27:54

Re: C struct problem

Inlägg av agehall »

Ja, det är väl ett exempel på när det är fullt motiverat att använda casts. Finns nog några till, men som sagt, varje gång man skriver en cast ska man fundera på varför.

Kan tillägga att även om jag kanske framstår som ett proffs som skriver felfri C-kod dagarna i ända så förekommer det en hel del cast:s i min kod - oftast pga lathet. Men det är också oftast kod som ingen annan ska använda och där jag är beredd att ta konsekvenserna av att det ibland blir mycket mer fel än vad jag tänkte från början.
Skriv svar