Forum: Mikrocontroller und Digitale Elektronik Bit auf Variable setzen?


von Steven (. (ovular) Benutzerseite


Lesenswert?

Hi,

gibt es etwas, womit man Folgendes vereinfachen kann.
Gerne auch was in ASM.
1
bool temp;
2
//...
3
PORTA = (PORTA & ~(1<<PA0)) | (temp<<PA0); //Pin soll je nach Variableninhalt gesetzt werden

Gruß
Ovu

von holger (Gast)


Lesenswert?

Was willst du da noch vereinfachen?

von c-hater (Gast)


Lesenswert?

Steven () schrieb:

> gibt es etwas, womit man Folgendes vereinfachen kann.

Da geht nix zu vereinfachen. Eigentlich ist es schon zu sehr 
vereinfacht, denn wie ein bool den Wert true intern repräsentiert, ist 
nicht einheitlich festgelegt, festgelegt ist nur, daß die binäre 
Repräsentation von true von 0 verschieden sein muß.

Es kann also gut passieren, dass es einen Compiler gibt, der den Code 
zwar übersetzt, aber trotzdem zur Laufzeit ein falsches Ergebnis 
produziert.

Richtig wäre also folgendes:

if (temp)
{
  PORTA = (PORTA | (1<<PA0));
}
else
{
  PORTA = (PORTA & ~(1<<PA0));
}

> Gerne auch was in ASM.

Da hast du exakt das gleiche Problem mit den bool. Dementsprechend müßte 
man auch in Asm auf !=0 prüfen und dann entsprechend des Ergebnisses 
verzweigen. Käme also in etwa sowas raus:

 lds reg,temp      ;2  2
 tst reg           ;1  1
 breq PC+2         ;1  2
 sbi PORTA,PORTA0  ;2
 brne PC+2         ;2  1
 cbi PORTA,PORTA0  ;   2
                   ;-  -
                    8  8

von Rolf M. (rmagnus)


Lesenswert?

c-hater schrieb:
> Da geht nix zu vereinfachen. Eigentlich ist es schon zu sehr
> vereinfacht, denn wie ein bool den Wert true intern repräsentiert, ist
> nicht einheitlich festgelegt, festgelegt ist nur, daß die binäre
> Repräsentation von true von 0 verschieden sein muß.

Die interessiert aber nicht. Es interessiert, was rauskommt, wenn der 
bool in einen int konvertiert wird, und das ist sehr wohl festgelegt.

von Max H. (hartl192)


Lesenswert?

Um welche Sprache geht es eigentlich? C? C++?

von Steven (. (ovular) Benutzerseite


Lesenswert?

Hi,

es geht um C. ATMega88PA


Danke schonmal, ich mach mir mal noch Gedanken...

Gruß
Ovu

von Max H. (hartl192)


Lesenswert?

Steven () schrieb:
> es geht um C

Ich wusste gar nicht dass es in C so etwas wie bool gibt.

von Steven (. (ovular) Benutzerseite


Lesenswert?

#include <stdbool.h>

von Thomas E. (thomase)


Lesenswert?

Rolf Magnus schrieb:
> Die interessiert aber nicht. Es interessiert, was rauskommt, wenn der
> bool in einen int konvertiert wird, und das ist sehr wohl festgelegt.

Den Typ Boolean gibt es in C nicht. Also kann da auch nichts konvertiert 
werden. Das Ergebnis einer Vergleiches ist immer Integer. Ungleich ist 
0, Gleich ist nicht 0, üblicherweise 1.

Dennoch ist das
1
#define FALSE 0
2
#define TRUE 1

falsch, sondern es muss heissen
1
#define FALSE 0
2
#define TRUE !0

Und das interessiert sehr wohl. Insbesondere in Anfängerprogrammen, wenn 
eine Abfrage if(x == 1) lautet, macht das Programm meistens nicht das, 
was es soll.

mfg.

von Paul B. (paul_baumann)


Lesenswert?

Max H. schrieb:
> Ich wusste gar nicht dass es in C so etwas wie bool gibt.

In C gibt es Alles:
#include <Halsbonbon.h>
#include <Lockenwickler.h>

;-)

MfG Paul

von Thomas E. (thomase)


Lesenswert?

Paul Baumann schrieb:
> In C gibt es Alles:
> #include <Halsbonbon.h>
> #include <Lockenwickler.h>

Fast alles.
1
#exclude <paul.b>

gibt es leider nicht.

mfg.

von Steven (. (ovular) Benutzerseite


Lesenswert?

:D

naja ich lass das jedenfallso so.
1
#define Power_set(x) Power_out_PORT = (Power_out_PORT & ~(1<<Power_outpin)) | (!(x)<<Power_outpin);    //x=true power on; x=false power off
2
Power_set(true); //hier optmiert er zu CBI

Und "übergebe" ich eine Variable führt er die entsprechenden Operationen 
aus. (selbstverständlich)

Optimieren lässt sich da wirklich nix.

In Assembler lässt sich auch nicht viel sparen.
Bei dem Code von C-Hater ließen sich noch zwei Taktzyklen sparen...


Gruß
Steven

von Tim S. (tim_seidel) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Rolf Magnus schrieb:
>> Die interessiert aber nicht. Es interessiert, was rauskommt, wenn der
>> bool in einen int konvertiert wird, und das ist sehr wohl festgelegt.
>
> Den Typ Boolean gibt es in C nicht. Also kann da auch nichts konvertiert
> werden. Das Ergebnis einer Vergleiches ist immer Integer. Ungleich ist
> 0, Gleich ist nicht 0, üblicherweise 1.

In C99 (ISO 9899) existiert der Typ Boolean, er heisst _Bool. bool ist 
ein Makro, dass auf ihn aufgelöst wird.

Er muss mindestens die Werte 0 und 1 aufnehmen können.

Eine Konversion von einem skalaren Datentyp in bool ergibt genau dann 0, 
wenn der Skalar 0 ist und 1 in jedem anderen Fall.

Daher muss nach C99
1
#define TRUE     1
2
3
int wert = 99 ;
4
bool istNull = wert ;
5
if (istNull == TRUE)
6
  printf("Doh!") ;
7
else
8
  printf("Donuts!") ;

ein Doh! ausgeben.

Warum?
Ich zitiere mal C99:
> 6.3.1.2 Boolean type
> 1 When any scalar value is converted to _Bool, the result is 0 if the
> value compares equal to 0; otherwise, the result is 1

Es gilt also bei bool istNull = wert ; der "otherwise" Fall. istNull ist 
daher 1.
Der Werte Vergleich 1 == 1 ist daher wahr und printf("Doh!") 
auszuführen.

Du siehst, ich kann durchaus einen boolean mit 1 vergleichen und bekomme 
immer das richtige Ergebnis.
Allerdings, und da ist das Problem mit den makros TRUE und FALSE 
besonders in der WinAPI: wird das Ergebnis nicht als bool sondern als 
anderer Skalar geliefert, so ist das Ergebnis ein Anderes, wie leicht zu 
sehen, wenn man die casts explizit aufschreibt:
1
    ((bool)99 == (bool)1) oder ((bool)99 == (int)1)
2
<=> ((bool)99 == 1) 
3
<=> (1 == 1)
4
<=> 1
5
6
    ((int)99 == (bool)1) oder ((int)99 == (int)1)
7
<=> ((int)99 == 1) 
8
<=> (99 == 1)
9
<=> 0

von Thomas E. (thomase)


Lesenswert?

Tim Seidel schrieb:
> #define TRUE     1
>
> int wert = 99 ;
> bool istNull = wert ;
> if (istNull == TRUE)

Aber if(wert == TRUE) geht schief. Darum geht es. Denn das liest man in 
Anfängerprogrammen mindestens einmal die Woche.

Dafür hättest du aber nicht nach dem C-Standard googeln müssen.

und sowas
1
int wert = 99 ;
2
bool istNull = wert ;
3
if (istNull == TRUE)

sieht man höchstens in einer Klausur.

Um einen Integer auf 1 zu zwingen macht man sowas: !!wert.

Willkommen in der Realität.

mfg.

von Tim S. (tim_seidel) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Tim Seidel schrieb:
>> #define TRUE     1
>>
>> int wert = 99 ;
>> bool istNull = wert ;
>> if (istNull == TRUE)
>
> Aber if(wert == TRUE) geht schief. Darum geht es. Denn das liest man in
> Anfängerprogrammen mindestens einmal die Woche.
>
> Dafür hättest du aber nicht nach dem C-Standard googeln müssen.
>
> und sowas
> int wert = 99 ;
> bool istNull = wert ;
> if (istNull == TRUE)
>
> sieht man höchstens in einer Klausur.

Ich nehme also an, du kennst die Realität aus der Uni. Also HiWi oder 
Dozent.
Das oben genannte Konstrukt ist durchaus üblich und abseits der Klausur 
relevant. Ich kann dir das "eingekochte Beispiel" auch anders aufbauen:
1
bool GetEigenschaft(...)
2
{
3
  ...
4
  return (zwischenErgebnis & 0xDEADBEEF) ;
5
}
6
7
8
if (1 == PruefeEigenschaft(...))
9
 ...

Copy & Paste bei der nächsten Eigenschaft, die aber dann nicht bool 
sondern int liefert und schon hast du beide Fälle in einem Code.

Um nicht in diese Fallen zu laufen vermeidet man i.d.R. dies durch 
Strukturvorgaben. In C und in vielen Anwendungen wirst du dennoch auf 
diese Probleme stoßen und mit Sicherheit auf den ein oder anderen 
Programmierer, der die Problematik nicht verstanden hat.

Nicht umsonst gibt man z.B. mit MISRA viele Vorgaben, die solche 
Unachtsamkeiten vermeiden sollen.

> Um einen Integer auf 1 zu zwingen macht man sowas: !!wert.
>
> Willkommen in der Realität.
>
> mfg.

Macht man mit Sicherheit nicht. Da würd ich 1 nehmen ;-)
Aber ich weiss worauf du hinaus willst. Das jedoch ist ebenfalls zu kurz 
gedacht für diese Art der "Arbeitsoptimierung"

Das Programm wird nicht günstiger, schneller oder wartbarer, wenn ich 
weniger Zeichen im Quellcode nutze ;-)

Wenn ich ein bool haben will mach ich eins daraus (cast). Wenn ich eine 
Wertebereichsbeschränkung haben will nutze ich das einmal vor 20 Jahren 
hingetackerte CROP(wert, min, max) Makro mit deutlich größerer 
Lesbarkeit und Flexibilität.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Eckmann schrieb:

>> if (istNull == TRUE)
>
> Aber if(wert == TRUE) geht schief. Darum geht es. Denn das liest man in
> Anfängerprogrammen mindestens einmal die Woche.

Die vernünftigste Lösung ist es, den Satz
"In C ist weniger oft mehr"
ernst zu nehmen und
1
  if( istNull )
zu schreiben.
istNull ist bereits als boolscher Wert gedacht. Der ist bereits "TRUE" 
oder "FALSE" (im Sinne der logischen Definition von TRUE und FALSE). Es 
gibt daher keinen wirklichen Grund, das noch mal mit TRUE zu 
vergleichen.
Man schreibt ja auch nicht
1
  if( ( i > 5 ) == TRUE )

wenn etwas bereits ein boolscher Wert ist, dann wird der direkt 
verwendet. In der Negierung noch mit einem ! davor, aber das wars dann 
auch schon
1
  if( istNull )
2
     ...
3
4
  if( !istNull )
5
     ....

mit diesen doppelt gemoppelten expliziten Vergleichen auf TRUE oder 
FALSE schiesst man sich nur ins eigene Knie.

von Axel S. (a-za-z0-9)


Lesenswert?

c-hater schrieb:
> Richtig wäre also folgendes:
>
> if (temp)
> {
>   PORTA = (PORTA | (1<<PA0));
> }
> else
> {
>   PORTA = (PORTA & ~(1<<PA0));
> }

Ganz genau. Das ist nicht nur am besten lesbar, sondern wird auch zu 
schnellerem Code:
1
$cat test.c
2
#include <avr/io.h>
3
#include <stdbool.h>
4
5
void f1(bool x)
6
{
7
  PORTC= (PORTC & ~(1<<PC0)) | (x<<PC0);
8
}
9
10
void f2(bool x)
11
{
12
  if (x) PORTC= PORTC |  (1<<PC0);
13
  else   PORTC= PORTC & ~(1<<PC0);
14
}

Compilieren mit
1
avr-gcc -c -mmcu=atmega8 -save-temps -Os test.c
Und jetzt schauen wir uns test.s an. Funktion f1() wird in allen 
Optimierungsstufen so übersetzt:
1
        in r25,0x15
2
        andi r25,lo8(-2)
3
        or r25,r24
4
        out 0x15,r25
5
        ret

allerdings nur, so lange wir PC0 verwenden. Für andere Portbits muß der 
bool in r24 erst umgerechnet werden. Für PC3 kommt z.B. das raus;
1
        in r18,0x15
2
        ldi r19,lo8(8)
3
        mul r24,r19
4
        movw r24,r0
5
        clr __zero_reg__
6
        andi r18,lo8(-9)
7
        or r18,r24
8
        out 0x15,r18
9
        ret

Funktion f2() hingegen kommt so raus (mit -O, -O1, -Os)
1
        tst r24
2
        breq .L5
3
        sbi 0x15,0
4
        ret
5
.L5:
6
        cbi 0x15,0
7
        ret

In den Optimierungsstufen -O2 und höher hingegen so:
1
        cpse r24,__zero_reg__
2
        rjmp .L8
3
        cbi 0x15,0
4
        ret
5
.L8:
6
        sbi 0x15,0
7
        ret

Ein anderes Portbit in f2() führt lediglich zu einer anderen Bitnummer 
in den sbi bzw. cbi Befehlen.

Merksatz: Code der in C kompakt aussieht, wird deswegen noch lange nicht 
zu kompaktem Maschinencode.


XL

von Thomas E. (thomase)


Lesenswert?

Tim Seidel schrieb:
> Ich nehme also an, du kennst die Realität aus der Uni. Also HiWi oder
> Dozent.
Man muss schon ziemlich beschränkt sein, um das daraus zu schliesen:
>> sieht man höchstens in einer Klausur.

Du kannst noch so viel mit dem Standard wedeln.
Sowas "if((bool)x== TRUE)" macht niemand. Jedenfalls nicht freiwillig. 
Und falls doch, brauchst du dem nur die Drogen wegzunehmen.

mfg.

von Cyblord -. (cyblord)


Lesenswert?

Thomas Eckmann schrieb:

> Sowas "if((bool)x== TRUE)" macht niemand. Jedenfalls nicht freiwillig.
> Und falls doch, brauchst du dem nur die Drogen wegzunehmen.

Und stattdessen Alkohol geben. Trifft man den richtigen Pegel, schreibt 
man die besten Programme. Ist aber knifflig. Siehe hier: 
http://xkcd.com/323/

von c-hater (Gast)


Lesenswert?

Steven () schrieb:

> In Assembler lässt sich auch nicht viel sparen.
> Bei dem Code von C-Hater ließen sich noch zwei Taktzyklen sparen...

Wie?

Eigentlich nur, indem man irgendwas voraussetzt, was für den allgemeinen 
Fall nicht vorausgesetzt werden kann.

von Steven (. (ovular) Benutzerseite


Lesenswert?

@c-hater
wenn temp schon ein Arbeitsregister ist...


 tst R0            ;1  1
 breq PC+2         ;1  2
 sbi PORTA,PORTA0  ;2
 brne PC+2         ;2  1
 cbi PORTA,PORTA0  ;   2
                   -----
                    6  6


...oder nicht?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas Eckmann schrieb:
> Fast alles.
> #exclude <paul.b>
>
> gibt es leider nicht.
 Hmmm.
1
#ifdef __MeistensDaneben
2
    #include <ThomasEckmann>
3
#else
4
    #include <AllesAndere.h>
5
#endif

von Rolf M. (rmagnus)


Lesenswert?

Max H. schrieb:
> Steven () schrieb:
>> es geht um C
>
> Ich wusste gar nicht dass es in C so etwas wie bool gibt.

Dann ist dein Wissen aber aber auf einem ziemlich alten Stand. Das ist 
in C nämlich seit 15 Jahren schon Standard.

Thomas Eckmann schrieb:
> Den Typ Boolean gibt es in C nicht.

Und noch einer auf dem Stand vom letzten Jahrtausend.

Thomas Eckmann schrieb:
> Um einen Integer auf 1 zu zwingen macht man sowas: !!wert.
>
> Willkommen in der Realität.

Sowas habe ich bisher immer nur als Antwort gesehen, wenn jemand gefragt 
hat, wie "man" das macht. In der Realität, also echten Programmen, aber 
noch nicht. Da dann höchstens: wert ? 1 : 0. Das finde ich auch besser 
lesbar als die doppelte Invertierung.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

c-hater schrieb:
> denn wie ein bool den Wert true intern repräsentiert, ist
> nicht einheitlich festgelegt, festgelegt ist nur, daß die binäre
> Repräsentation von true von 0 verschieden sein muß.

true ist 1
 
1
C99 7.16 
2
3
1 The header <stdbool.h> defines four macros.
4
2 The macro "bool" expands to "_Bool".
5
3 The remaining three macros are suitable for use in #if
6
  preprocessing directives. They are "true" which expands
7
  to the integer constant 1, "false" which expands to the
8
  integer constant 0, and [...]

_Bool wiederum ist in C99 ein Typ:
 
1
C99 6.3.1.2 Boolean type
2
3
1 When any scalar value is converted to _Bool, the result
4
  is 0 if the value compares equal to 0; otherwise,
5
  the result is 1.


Thomas Eckmann schrieb:

> Den Typ Boolean gibt es in C nicht.

Siehe oben, auch wenn das Schlüsselwort nicht "Boolean" lautet.

> Dennoch ist das
>
1
> #define FALSE 0
2
> #define TRUE 1
3
>
>
> falsch, sondern es muss heissen
>
1
> #define FALSE 0
2
> #define TRUE !0
3
>

!0 war in C schon immer 1:
1
C99 6.5.3.3 Unary arithmetic operators
2
3
5 The result of the logical negation operator ! is 0 if the
4
  value of its operand compares unequal to 0, 1 if the value
5
  of its operand compares equal to 0. The result has type int.

Version #2 ist nur Zucker, mehr nicht. Und beide sind schlechter Stil da 
es true und false gibt, denn der OP schreibt offenbar in C99+.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.