C fallgrop ?

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
persika
EF Sponsor
Inlägg: 1336
Blev medlem: 31 juli 2006, 22:14:37
Ort: Österlen, Skåne

C fallgrop ?

Inlägg av persika »

MPLAB 8, Hitech C, PIC12F629

Jag har en funktion så här:

Kod: Markera allt

Boolean KnappTryckt()
{
return !GPIO3;
}
På ett annat ställe i programmet (i en slinga) anropade jag funktionen för att läsa av knappen:

Kod: Markera allt

    if (KnappTryckt)
      break;
Jag råkade göra ett slarvfel och glömde att det ska vara KnappTryckt() och inte enbart KnappTryckt.
Med mitt slarvfel blev det att villkoret alltid blev uppfyllt, och det hade jag ju inte tänkt.
Ingen varning eller felmeddelande från kompilatorn.
Varför blir det så här, hur kan kompilatorn godkänna detta ?
Användarvisningsbild
Klas-Kenny
Inlägg: 11292
Blev medlem: 17 maj 2010, 19:06:14
Ort: Växjö/Alvesta

Re: C fallgrop ?

Inlägg av Klas-Kenny »

KnappTryckt blir i det fallet en pekare till KnappTryckt(),

Kod som gör samma sak som du skriver, men mer förståeligt är:

Kod: Markera allt

Boolean (*funkPtr)(void) = (Boolean*)KnappTryckt;
if(funkPtr) {
...
}
I det fallet kollar man alltså på minnesadressen till där funktionen KnappTryckt() finns. Om den adressen inte är noll, uppfylls villkoret.


Om man *vill* göra enligt ovan, men att faktiskt använda funktionen, skulle man göra:

Kod: Markera allt

Boolean (*funkPtr)(void) = (Boolean*)KnappTryckt;
if(funkPtr()) {  // Notera () som ger funktionen istället för adressen
...
}
Edit: För sällan man pillar med sådant, fixade så att exempelkoden kan fungera...
Senast redigerad av Klas-Kenny 22 maj 2018, 11:27:32, redigerad totalt 1 gång.
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: C fallgrop ?

Inlägg av adent »

Jag tror det måste vara: Boolean (* funkPtr)(void)

Annars blir det bara en Boolean-pointer.

Edit: men nog borde kompilatorn ha varnat iaf!
Användarvisningsbild
Klas-Kenny
Inlägg: 11292
Blev medlem: 17 maj 2010, 19:06:14
Ort: Växjö/Alvesta

Re: C fallgrop ?

Inlägg av Klas-Kenny »

Finns ju egentligen ingen anledning för kompilatorn att varna. Att kolla om funktionspekare är skiljda från noll är inget konstigt..

Vill man få varningar för den typen av fel så får man skriva typ

Kod: Markera allt

if(KnappTryckt == TRUE)
Då kommer kompilatorn varna för jämförelse av olika datatyper.
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: C fallgrop ?

Inlägg av adent »

Kod: Markera allt

#include <stdio.h>
#include <stdlib.h>

int foo(void);

int main(int argc, char *argv[])
{
  if(foo)
  {
    printf("foo\n");
  }

  return EXIT_SUCCESS;
}

adent: {50} gcc fooobar.c -o fb
fooobar.c: In function 'main':
fooobar.c:8: warning: the address of 'foo', will always evaluate as 'true'
adent: {51}
Edit: du har rätt gällande en explicit funktionspekare, då varnar den inte. Fast det var inte det som hände:

Kod: Markera allt

#include <stdio.h>
#include <stdlib.h>

int foo(void);

int (*fooptr)(void) = foo;

int main(int argc, char *argv[])
{
  foo();

  if(fooptr)
  {
    fooptr();
    printf("foo\n");
  }

  return EXIT_SUCCESS;
}

int foo(void)
{
  printf("I am foo!\n");
}

adent: {56} gcc fooobar.c -o fb
adent: {57}
Användarvisningsbild
Klas-Kenny
Inlägg: 11292
Blev medlem: 17 maj 2010, 19:06:14
Ort: Växjö/Alvesta

Re: C fallgrop ?

Inlägg av Klas-Kenny »

Sedär, beror på kompilatorflaggor då, om den varnar eller ej...

Kollade i MPLAB X som jag sitter i för stunden, och fick först ingen varning när jag gjorde likadant.
Men i inställningarna för kompilatorn (xc32) fanns en inställning att markera "Additional warnings", då började den varna på exakt samma sätt som du fick fram.

Nu är väl inte Hitech C GCC-baserad som xc32, men kanske finns där någon liknande inställning ändå....
persika
EF Sponsor
Inlägg: 1336
Blev medlem: 31 juli 2006, 22:14:37
Ort: Österlen, Skåne

Re: C fallgrop ?

Inlägg av persika »

Tack för svar, så nu vet jag detta.
Lite konstigt ändå, varför skulle man vilja se om adressen till en funktion är =noll, när det är en funktion som ligger fast i programminet, den kommer aldrig att vara =noll. Lättare att förstå nyttan av det här när det är en pekarvariabel (som pekar till en funktion). Då skulle man kunna se om pekarvariabeln fått nåt värde eller ej.

Det går att göra mycket med C, men ibland kan det vara lite kryptiskt och läsbarheten av koden är inte helt solklar.

Hittade inte nån inställning för att få en varning om detta, i MPLAB 8 och Hitech C.
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: C fallgrop ?

Inlägg av adent »

Mjo, fast det är lite typiskt för C. Att göra som programmeraren säger.
Men jag gissar att just din kompilator antagligen behandlar en funktion och en funktionspekare lika.

t.ex.

if(a == b)

och

if(a = b)

är ju bägge giltiga, men gör väldigt olika saker :)
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: C fallgrop ?

Inlägg av johano »

I boken "Writing solid code" (rekommenderas starkt) lärde man ut vad de kallade "defensiv programmering" - en teknik
för att undvika buggar. T.ex. så placerar man alltid konstanten till vänster i villkorsuttryck, ett glömt "=" ger då ett
kompilatorfel istället för en stygg logisk bugg.

Kod: Markera allt

if( a = TRUE ) {} // legalt men förmodligen inte vad som avsågs

if( TRUE = a ) {} // ger ett kompilatorfel

I de flesta fall där man _inte_ glömmer det "extra" '='-tecknet så betyder uttrycken exakt samma sak:

Kod: Markera allt

if( a == TRUE ) {}

if( TRUE == a ) {}
/j
kodar-holger
EF Sponsor
Inlägg: 916
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: C fallgrop ?

Inlägg av kodar-holger »

Grejen är ju den att man normalt inte utvärderar vad något används till utan använder konstruktionen som den är definierad.

foo betyder helt enkelt pekaren till funktionen
foo() betyder värdet som funktionen returnerar.

Om du sen stoppar in det i villkorsdelen på en if eller som högerledet i en tilldelning är egalt för språket. Tråkigt nog.

Samma samma med = kontra ==. Båda returnerar något värde. Om tilldelningsoperatorn = inte returnerade ett värde hade säkert 90% av alla fel i C/C++ försvunnit (något överdrivet, jag vet).

Finns det en varningsnivå man kan välja? Sätt den så högt du kan. Finns alternativet att behandla varningar som fel så slå på det också. I den programvara jag underhåller dagligdags som har några hundra tusen rader kod hitta vi ett 10-tal = i if när jag höjde varningsnivån vid kompilering. Buggar vare sig vi eller tack och lov kunden hittat.
persika
EF Sponsor
Inlägg: 1336
Blev medlem: 31 juli 2006, 22:14:37
Ort: Österlen, Skåne

Re: C fallgrop ?

Inlägg av persika »

Ett annat misstag jag gjorde nyligen var så här:

Kod: Markera allt

// en boolsk variabel som ska visa om man är i pause-läge

Boolean IPause;

// ändra till motsatt pause-läge

IPause != IPause;


Fel!


Ska vara så här:

Kod: Markera allt


IPause = !IPause;
I det senare alternativet tilldelas variabeln ett nytt värde. I det första fallet görs bara en jämförelse vars resultat aldrig används, men det ”svalde” kompilatorn utan klagomål!
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: C fallgrop ?

Inlägg av johano »

Ja, den är lätt att göra fel på då den följer "mönstret" av de andra 'tilldelningsoperatorerna' som &=, ^= och |=
hummel
Inlägg: 2259
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

Re: C fallgrop ?

Inlägg av hummel »

MISRA C är en bra att följa vid C-programmering just för att undvika fällor som beskrivits ovan.

https://en.wikipedia.org/wiki/MISRA_C
Skriv svar