Sida 1 av 1

C fallgrop ?

Postat: 22 maj 2018, 09:52:21
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 ?

Re: C fallgrop ?

Postat: 22 maj 2018, 10:50:11
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...

Re: C fallgrop ?

Postat: 22 maj 2018, 11:08:38
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!

Re: C fallgrop ?

Postat: 22 maj 2018, 11:42:29
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.

Re: C fallgrop ?

Postat: 22 maj 2018, 12:30:17
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}

Re: C fallgrop ?

Postat: 22 maj 2018, 13:16:48
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å....

Re: C fallgrop ?

Postat: 23 maj 2018, 09:49:31
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.

Re: C fallgrop ?

Postat: 23 maj 2018, 09:55:31
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 :)

Re: C fallgrop ?

Postat: 23 maj 2018, 10:09:38
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

Re: C fallgrop ?

Postat: 23 maj 2018, 11:09:15
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.

Re: C fallgrop ?

Postat: 13 juni 2018, 14:43:02
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!

Re: C fallgrop ?

Postat: 13 juni 2018, 14:54:15
av johano
Ja, den är lätt att göra fel på då den följer "mönstret" av de andra 'tilldelningsoperatorerna' som &=, ^= och |=

Re: C fallgrop ?

Postat: 13 juni 2018, 15:53:35
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