Forum: Compiler & IDEs rechnet der preprocessor in C gcc (AVR) multiplikation aus?


von Joachim B. (jar)


Lesenswert?

wie im Titel:

rechnet der preprocessor in C gcc (AVR) Multiplikation aus?

#define CONST1 10
#define CONST2 20

(CONST1 x CONST2)

oder

#define MUL (CONST1 x CONST2)

oder muss das der AVR zur Laufzeit rechnen?

: Verschoben durch Admin
von Peter II (Gast)


Lesenswert?

Joachim B. schrieb:
> rechnet der preprocessor in C gcc (AVR) Multiplikation aus?

nein, dafür ist er nicht zuständig

> oder muss das der AVR zur Laufzeit rechnen?
auch nein, das macht, wenn eingeschaltet, der Optimierer.

von Joachim B. (jar)


Lesenswert?

Peter II schrieb:
> auch nein, das macht, wenn eingeschaltet, der Optimierer.

-OS ?

von Hermann (Gast)


Lesenswert?

Peter II schrieb:
> Joachim B. schrieb:
>> rechnet der preprocessor in C gcc (AVR) Multiplikation aus?
>
> nein, dafür ist er nicht zuständig

In BASCOM ist das mal wieder super einfach:
Const Mul = Const1 * Const2 / Const3 ...

Ich wollte schon mit GCC anfangen, weil ihr das so liebt. Das werde ich 
erst mal lassen. Da muss man ja anscheinend alles von Hand stricken.

von public (Gast)


Lesenswert?

also eigentlich wird der Wert CONST1 mit deinem definierten Wert ersetzt 
und CONST2 mit dem anderen. des weiteren wird der wert MUL dann mit dem 
entstehenden Ausdruck ersetzt also 10x20

willst du denn multiplizieren oder ein x dazwischenschreiben oder hast 
du das nur zur verdeutlichung so geschrieben?

beste grüße
public

von nicht"Gast" (Gast)


Lesenswert?

Hermann schrieb:
> Peter II schrieb:
>> Joachim B. schrieb:
>>> rechnet der preprocessor in C gcc (AVR) Multiplikation aus?
>>
>> nein, dafür ist er nicht zuständig
>
> In BASCOM ist das mal wieder super einfach:
> Const Mul = Const1 * Const2 / Const3 ...
>
> Ich wollte schon mit GCC anfangen, weil ihr das so liebt. Das werde ich
> erst mal lassen. Da muss man ja anscheinend alles von Hand stricken.

Hm,

komischer Beitrag. Gibts dafür einen tieferen Sinn?

Bei deinem Beispiel. Wird das jetzt vom Compiler ausgerechnet oder zur 
Laufzeit vom Controller? Und überhaupt, warum blinkt hier Mawins LED 
rum? :)

Ach, zum Thema. Der Präprozessor rechnet gar nichts aus. Der macht nur 
eine Textersetzung. Der Compiler rechnet rum.

Grüße,

von public (Gast)


Lesenswert?

Hermann schrieb:
> In BASCOM ist das mal wieder super einfach:
> Const Mul = Const1 * Const2 / Const3 ...
>
> Ich wollte schon mit GCC anfangen, weil ihr das so liebt. Das werde ich
> erst mal lassen. Da muss man ja anscheinend alles von Hand stricken.

das kannst du genau so auch in C machen, mit #define definierst du dir 
einen symbolischen Ausdruck. das schlüsselwort für Konstanten ist
1
const

grüße

von npn (Gast)


Lesenswert?

Hermann schrieb:
> Peter II schrieb:
>> Joachim B. schrieb:
>>> rechnet der preprocessor in C gcc (AVR) Multiplikation aus?
>>
>> nein, dafür ist er nicht zuständig
>
> In BASCOM ist das mal wieder super einfach:
> Const Mul = Const1 * Const2 / Const3 ...
>
> Ich wollte schon mit GCC anfangen, weil ihr das so liebt. Das werde ich
> erst mal lassen. Da muss man ja anscheinend alles von Hand stricken.

Kann man wirklich mittlerweile bei BASCOM mehr als eine Operation pro 
Zeile schreiben? Ich kenne noch den Stand, daß man einen 
Berechnungsausdruck in einzelne Operationen zerlegen mußte und pro Zeile 
nur eine Berechnung möglich war. Also z.B.
1
Mul = Const1 * Const2
2
Mul = Mul / Const3
Das war eine von unzähligen Sachen, die mich unheimlich genervt haben...

von Peter II (Gast)


Lesenswert?

Hermann schrieb:
> Ich wollte schon mit GCC anfangen, weil ihr das so liebt. Das werde ich
> erst mal lassen. Da muss man ja anscheinend alles von Hand stricken.

das versteht ich nicht, was musst du denn von Hand machen wenn es schon 
der Compiler kann?

von jemand (Gast)


Lesenswert?

folgender Quelltext:
1
#include <stdio.h>
2
3
#define FOO 3
4
#define BAR 4
5
6
int main()
7
{
8
    int a = FOO * BAR;
9
    printf("%d\n", a);
10
    return 0;
11
}

der Präprozessor macht daraus
1
...
2
    int a = 3 * 4;
3
...

und der gcc, ganz ohne Optimierungen
1
...
2
  400535:  c7 45 fc 0c 00 00 00   movl   $0xc,-0x4(%rbp)
3
...

3*4 wird also ausgewertet zu 12, bzw. 0xc

von DirkB (Gast)


Lesenswert?

Beim #if rechnet der Präprozessor.

von Peter D. (peda)


Lesenswert?

Der C-Complier ist ein fauler Hund. Er versucht so wenig wie möglich und 
so spät wie möglich Code zu erzeugen.

Wenn er irgendwie mitkriegt, daß ein Ausdruck aus bereits bekannten 
Werten besteht, rechnet er ihn aus und trägt nur das Ergebnis in den 
Code ein.
Das muß nichtmal ein define oder ein const sein:
1
int main(void)
2
{
3
  uint8_t x;
4
  
5
  x = 20;
6
  DDRB = 7;
7
  22:  87 e0         ldi  r24, 0x07  ; 7
8
  24:  87 bb         out  0x17, r24  ; 23
9
  PORTB = x / 5;
10
  26:  84 e0         ldi  r24, 0x04  ; 4
11
  28:  88 bb         out  0x18, r24  ; 24

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Peter Dannegger schrieb:
> Der C-Complier ist ein fauler Hund. Er versucht so wenig wie möglich und
> so spät wie möglich Code zu erzeugen.
>
> Wenn er irgendwie mitkriegt, daß ein Ausdruck aus bereits bekannten
> Werten besteht, rechnet er ihn aus und trägt nur das Ergebnis in den
> Code ein.

danke Peter,

ich habe 2 Geradengleichungen mit 2 Steigungen m (dY/dX) und trage die 
als (double) getrennt in den Header, im Proggi ist die resultierende 
Gleichung aber das Produkt der beiden "m", da die "m" aber separat 
ermittelt werden würde ich die gerne jeweils eigenständig im #define 
lassen, aber der avr soll die Mul auch nicht immer rechnen, ohne weitere 
Untersuchungen kann ich dir also glauben das die MUL keine x Takte 
verbraucht?

danke

von Peter D. (peda)


Lesenswert?

Glauben kannst Du nur dem Assemblerlisting.

von Stefan F. (Gast)


Lesenswert?

Mathematische Ausdrücke werden vollständig optimiert, wenn sie aus 
Konstanten bestehen (wie in den obigen Beispielen). Darauf kannst du 
dich absolut verlassen.

Und wer es wirklich wissen will, schaut in den erzeugten Assembler Code.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> wie im Titel:
>
> rechnet der preprocessor in C gcc (AVR) Multiplikation aus?

Ja und nein.  Kommt auf deinen Code an.

von Besucher (Gast)


Lesenswert?

Joachim B. schrieb:
> ohne weitere Untersuchungen kann ich dir also glauben das die MUL
> keine x Takte verbraucht?

Das ist eine grundlegende Compileroptimierung, bekannt als constant 
propagation. Musst halt mal in die Doku deines Compilers schauen wie der 
das handhabt. Oder du schreibst dir eben ein Testprogramm, lässt es in 
beiden Varianten laufen, und stellst dich mit der Stoppuhr daneben. Oder 
du vergleichst die Objektdateien der beiden Varianten, wenn sie gleich 
sind wäre das schon ein gutes Indiz. Oder, wenn du tatsächlich ganz ohne 
Untersuchungen auskommen möchtest, dann musst du Peter wohl einfach 
glauben. ;-)

von Joachim B. (jar)


Lesenswert?

Peter Dannegger schrieb:
> Glauben kannst Du nur dem Assemblerlisting.

da schaue ich nicht rein, dann glaube ich lieber dir,

Besucher schrieb:
> Oder du schreibst dir eben ein Testprogramm, lässt es in
> beiden Varianten laufen, und stellst dich mit der Stoppuhr daneben.

nö, wenn dann:

#define CONST1 (double)0.0055678
#define CONST2 (double)0.0123456
#define MUL (CONST1 * CONST2)
(double) a;

Port setzen
a=MUL;
Port rücksetzen

mit dem Oszi die Zeit begucken

if < 20 (Takte wurde vorher gerechnet)
else (Takte zur Laufzeit gerechnet)

: Bearbeitet durch User
von DirkB (Gast)


Lesenswert?

Der Ausdruck wird vom Compiler berechnet (nicht im Programm zur 
Laufzeit und auch nicht vom Präprozessor).

von Noch einer (Gast)


Lesenswert?

> Glauben kannst Du nur dem Assemblerlisting.
Nur solange niemand ein LLVM Backend für AVR schreibt.

von Hermann (Gast)


Lesenswert?

npn schrieb:
> Kann man wirklich mittlerweile bei BASCOM mehr als eine Operation pro
> Zeile schreiben?

Nein, das kann man zur Laufzeit immer noch nicht. Das nervt mich auch. 
Aber bei der Definition der Konstanten geht das.

Peter II schrieb:
> das versteht ich nicht, was musst du denn von Hand machen wenn es schon
> der Compiler kann?

Es macht einfach den Eindruck, dass bei C alles kompliziert ist. Wie 
kommt es bloß, dass einer das Statement
PORTB = (PORTB & ~(1 << PB0)) | ((ACSR & (1 << ACO)) >> ACO) << PB0; 
vorschlägt, was man das auch mit PORTB.0= ACSR.AC0 machen kann? ( siehe 
hier)
Beitrag "Re: Ein Bit setzten"
Es scheint bei C-Programmierern eine Sucht zu sein, sich mit unlesbaren 
Konstrukten zu überbieten.

Ich habe immer noch nicht die Antwort auf die erste Frage 
herausgefunden, ob man wie in Bascom eine Konstante als mathematischen 
Ausdruck hinschreiben kann - anscheinend nicht!
Das ist aber ganz praktisch, wenn man z.B. einen Programm-Takt mit einem 
Zählerüberlauf machen will:
const Quarz = 4000000
const Prescale = 1024
const Takt = 20
const Timset = 256-Quarz/Prescale/Takt

In C geht das nach meinem jetzigen Verständnis nur mit
#Define Konstante Wert
Den Ausdruck muss man dann ins Programm schreiben. Ja, ich weiß, der 
Compiler rechet das vorher. Es ist aber viel übersichtlicher, wenn man 
die festen Berechnungen in die Konstanten auslagert.
Im Programm steht dann nur nach jedem Überlauf
Timer1 = Timset

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hermann schrieb:
> das auch mit PORTB.0= ACSR.AC0 machen kann?

Das ist kein C, sondern eine Sprache, die nur so aussieht wie C.

Ein Bitfeldname kann keine Zahl sein.

> Ich habe immer noch nicht die Antwort auf die erste Frage
> herausgefunden, ob man wie in Bascom eine Konstante als mathematischen
> Ausdruck hinschreiben kann - anscheinend nicht!

Im Gegensatz zu Bascom kannst du das überall so schreiben, nicht
nur bei einer Konstante, sondern auch in Ausdrücken.

Deine Frage hattest du aber auf den Präprozessor formuliert, daher
hast du auch die Antworten dafür bekommen.  Die von dir gewünschte
Funktionalität erledigt nicht der Präprozessor, sondern der Compiler
selbst.

> const Quarz = 4000000
> const Prescale = 1024
> const Takt = 20
> const Timset = 256-Quarz/Prescale/Takt
>
> In C geht das nach meinem jetzigen Verständnis nur mit
> #Define Konstante Wert

Jein.

C kennt zwar “const”, aber das sind erstmal syntaktisch nur Variablen,
die du nicht ändern darfst (im Gegensatz zu C++, was echte Konstanten
hat).

Bei deinen einfachen Dingen wirst du aber zwischen beiden keinen
Unterschied merken, daher kannst du durchaus sowas machen:
1
const long int Quarz = 4000000; /* long int, da int bei AVR nur bis 32767 geht */
2
const int Prescale = 1000;
3
const int Takt = 20;
4
const int Timset = 256 - Quarz / Prescale / Takt;

C hat halt Datentypen, die musst du schon angeben.

: Bearbeitet durch Moderator
von Karl M. (Gast)


Lesenswert?

Hallo Hermann ,

doch Konstanten gibt es in C const <datentype> <name> = <expr>;

von Hermann (Gast)


Lesenswert?

Jörg Wunsch schrieb:
>> das auch mit PORTB.0= ACSR.AC0 machen kann?
>
> Das ist kein C, sondern eine Sprache, die nur so aussieht wie C.
>
> Ein Bitfeldname kann keine Zahl sein.

Da ich mir C noch nicht reingezogen habe, und keiner widersprochen hat, 
musste ich das glauben:
Beitrag "Re: Ein Bit setzten"
Dann bleibt das in C eben umständlich.

Jörg Wunsch schrieb:
> Bei deinen einfachen Dingen wirst du aber zwischen beiden keinen
> Unterschied merken, daher kannst du durchaus sowas machen:
> const long int Quarz = 4000000; /* long int, da int bei AVR nur bis
> 32767 geht */
> const int Prescale = 1000;
> const int Takt = 20;
> const int Timset = 256 - Quarz  Prescale  Takt;
>
> C hat halt Datentypen, die musst du schon angeben.

Ja, das ist doch super. Warum sagt das dem Fragesteller nicht gleich 
einer. Ob nun Preprocessor oder Compiler ist doch egal. Und das mit den 
Datentypen ist sowieso besser. Da fällt man bei Bascom öfter rein, weil 
er aus einer Division ein Float macht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hermann schrieb:

> Dann bleibt das in C eben umständlich.

Die Umständlichkeit haben wir Atmel zu verdanken.  Sie hätten die
Bitnamen auch gleich passend vergeben können (haben sie dann beim
Xmega so gemacht), also statt
1
PORTB = 1 << PB2;

(mit PB0 = 2) schreibt man
1
PORTB = PB0;

(mit PB0 = 0x04).

Da hätte allerdings der Assembler bei einem SBI-Befehl aus der
Bitmaske (0x04) die Bitnummer (2) für den Opcode ermitteln müssen.
Sollte auch Ende des letzten Jahrtausends aber durchaus im Bereich
der Möglichkeiten gelegen haben … die Chance haben sie aber leider
verpasst.

> Ja, das ist doch super. Warum sagt das dem Fragesteller nicht gleich
> einer.

Weil seine Frage nicht so klang, als wäre es ihm genau darauf
angekommen.

> Ob nun Preprocessor oder Compiler ist doch egal.

Im Prinzip ja, aber warum fragt der dann nach dem Präprozessor?

Vermutlich ist es einfach nur ein gängiges Missverständnis, dass man
alles, was zur Compilezeit vor der eigentlichen Codeerzeugung passiert,
gern dem „Präprozessor“ anlastet.  Der Präprozessor ist aber bei C
halt recht klar umrissen, und er macht weiter nichts als einfache
Textersetzungen.  (Lediglich für bedingte Compilierung rechnet er
auch, um den Bedinungs-Ausdruck zu ermitteln.)

von Noch einer (Gast)


Lesenswert?

>> das auch mit PORTB.0= ACSR.AC0 machen kann?
>Das ist kein C, sondern eine Sprache, die nur so aussieht wie C.

Nanu? Soweit ich den Standard verstehe, ist diese Art von Bitfeldern in 
ISO/IEC 9899 6.7.2.1 definiert. Wieso ist das kein C?

von Noch einer (Gast)


Lesenswert?

Ähm.. Copy&Paste Fehler. Natürlich: PORTB.B0= ACSR.AC0

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Noch einer schrieb:
> Natürlich: PORTB.B0= ACSR.AC0

Yep, so geht's.

von Hermann (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Yep, so geht's.

Ich fass es nicht!
Eine ganz einfache Frage und keiner merkt, dass man statt
#define einfach nur Const schreiben muss.

In dem anderen Thread gibt es endlose Konstrukte um ein Bit zu setzen, 
dabei geht es mit einem einfachen Bitfeld.

C-Programmierer wollen eben nicht einfach denken. Da reicht ein falscher 
Begriff und es gibt nur noch Missverständnisse.

von Noch einer (Gast)


Lesenswert?

C hat alle Konstruktionen, die sich in den letzten 40 Jahren ansammelten 
immer noch beibehalten.

1972 hielten Kernighan und Ritchie so ein #define, oder auch die 
Bitfummelelei mit |= für eine gute Idee.

Heutzutage finden viele const und Bitfelder besser. Und der ganze 
Programmierstiel hat kaum noch was mit C von 1972 zu tun.

Bascom war da konsequent. Hat alles aus dem 1964er Basic rausgeworfen, 
was nicht mehr unbedingt gebraucht wird.

Missverständnisse entstehen, weil es in C so viele unterschiedliche 
Möglichkeiten gibt. Dazu kommt dann noch: Der eine redet über 
Performance, der andere über Wartbarkeit und der dritte über 
Portabilität.

Niemand schreibt in Bascom z.B. einen portablen USB-Treiber. Da können 
die Probleme, über die hier diskutiert werden, gar nicht aufkommen.

von Joachim B. (jar)


Lesenswert?

Noch einer schrieb:
> Dazu kommt dann noch: Der eine redet über
> Performance, der andere über Wartbarkeit und der dritte über
> Portabilität.

und deswegen bleibe ich trotz Arduinonutzung beim "72er Kernighan und 
Ritchie" Code, kann den jederzeit nach Atmel Studio portieren auf 
eigenen Schaltungen.

Klar könnte man anders, aber warum sollte man?

wenn doch -0s default eingestellt ist bei beiden Varianten mit gcc ein

PORTB |= (1<<3);

ein SBI generiert laut vieler Aussagen hier.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Jörg Wunsch schrieb:
> Noch einer schrieb:
>> Natürlich: PORTB.B0= ACSR.AC0
>
> Yep, so geht's.

Hermann schrieb:
> Ich fass es nicht!
> Eine ganz einfache Frage und keiner merkt, dass man statt
> #define einfach nur Const schreiben muss.
>
> In dem anderen Thread gibt es endlose Konstrukte um ein Bit zu setzen,
> dabei geht es mit einem einfachen Bitfeld.

Das Problem dabei ist nur, dass in den Header-Files der AVR Libc diese
Bitfelder nicht deklariert sind. Es müsste sich also jemand hinsetzen
und diese Deklarationen für jedes I/O-Register und für jeden AVR-Typ
schreiben. Das ist bisher halt nicht passiert.

von Stefan F. (Gast)


Lesenswert?

In C kann man sich auch Markos definieren, die das Setzen von Bits 
leichter lesbar machen.

Mein Favorit:
1
#define LED_ON PORTB |= 4
2
#define LED_OFF PORTB &= ~4;
3
4
void main() {
5
   LED_ON;
6
   _delay_ms(1000);
7
   LED_OFF;
8
}

Dem Joachim gefällt es so vielleicht besser:
1
#define writeBit(port,bit,value) { if ((value)>0) (port) |= (1<<bit); else (port) &= ~(1<<bit); } 
2
3
void main() {
4
    writeBit(PORTB,4,1);
5
    _delay_ms(1000);
6
    writeBit(PORTB,4,0);
7
}

Hier im Forum wurden bereits viele andere alternative Markos diskutiert.

Das schöne bei C ist, dann man es sich so zurecht basteln kann, wie man 
es gerne haben möchte.

Was ich viel hilfreicher finde, ist eine Besonderheit bei Xmega 
Controllern: Die Special-Function Register haben alle immer die gleiche 
Reihenfolge. Also alle Register von PORT A liegen direkt hintereinander 
im Speicher, und die Register von Port B, C, D, E usw. haben genau die 
gleiche Reihenfolge, wie bei Port A. Gleiches gilt für Serielle Ports, 
Timer und alle sonstigen Funktionen, die mehrfach existieren.

Wegen dieser Eigenschaft wurde es möglich (und auch gemacht), die Ports 
als Struktur zu definieren. Dann wiederum kann man Ports als 
Funktionsargumete übergeben. Zum Beispiel so:
1
void main() {
2
    sende(USARTC0,"Hallo");
3
    sende(USARFE0,"Wer ist da?);
4
}

Die Funktion sende() kann dann auf alle Register des übergebenen 
seriellen Ports zugreifen. Sie selbst ist jedoch (ohne eine zusätzliche 
Zeile Code) so generisch geschrieben, dass sie mit jedem seriellen Port 
aufgerufen werden kann.

von Stefan F. (Gast)


Lesenswert?

> Es müsste sich also jemand hinsetzen
> und diese Deklarationen für jedes I/O-Register
> und für jeden AVR-Typ schreiben. Das ist bisher halt nicht passiert.

Was ganz sicher daran liegt, dass dieses Problem nicht wichtig ist.

Diese ewigen Diskussionen der Art "Meine Programmiersprache ist besser 
als deine" ist meiner Meinung nach nur für Anfänger verlockend. 
Erfahrenen Programmierern ist ziemlich wurscht, in welcher Sprache sie 
programmieren.

Ich habe noch kein Projekt gesehen, das wegen der falschen Sprache 
gescheitert ist.

von Joachim B. (jar)


Lesenswert?

Stefan Us schrieb:
> Dem Joachim gefällt es so vielleicht besser:

nö,

mir gefällt im Header:
1
#define TS_MASS1_PLUS   p.x < 60 &&  p.y > 48 && p.y < 112 && tft1_col==ILI9341_GREEN

in der loop:
1
    if( TS_MASS1_PLUS )
2
    { if(dezi_mass1<7000)
3
      { dezi_mass1 += 1000;
4
        Serial.print(F("MASS 1 = (")); Serial.print(dac_setzen(MASS1, dezi_mass1)); MassScreen(SCREEN_PRT, MASS1);
5
        mass1_digits = lese_analog(MASS1_ADC); // eigene Routine mit 32 Lesungen und Mittelwert

wobei die Serial.prints vermutlich später rausfliegen oder durch 
DEBUG_PRINT ersetzt werden.

und Ports setzen und löschen

Header:
1
#if (ARDUINO>0)
2
  #if ARDUINO >= 100
3
    #define printIIC(args) Wire.write((uint8_t)args)
4
    #define readIIC() Wire.read()
5
  #else
6
    #define printIIC(args) Wire.send(args)
7
    #define readIIC() Wire.receive()
8
  #endif
9
10
#if defined(__AVR_ATmega328P__) || defined(M1284P_TIM1)
11
  #define ARDUINO_LED      5
12
  #define DDR_ARDUINO_LED  DDRB
13
  #define PORT_ARDUINO_LED PORTB
14
  #define ARDUINO_LED_ON   PORT_ARDUINO_LED|=(1<<ARDUINO_LED)
15
  #define ARDUINO_LED_OFF  PORT_ARDUINO_LED&=~(1<<ARDUINO_LED)
16
17
#elif defined(__AVR_ATmega1284P__)
18
  #define ARDUINO_LED      7
19
  #define DDR_ARDUINO_LED  DDRB
20
  #define PORT_ARDUINO_LED PORTB
21
  #define ARDUINO_LED_ON   PORT_ARDUINO_LED|=(1<<ARDUINO_LED)
22
  #define ARDUINO_LED_OFF  PORT_ARDUINO_LED&=~(1<<ARDUINO_LED)
23
#endif
24
25
// der #else Teil für pures C mit Fleury I2C Lib ist hier entfallen
26
27
#endif

von Dr. Sommer (Gast)


Lesenswert?

Stefan Us schrieb:
> Erfahrenen Programmierern ist ziemlich wurscht, in welcher Sprache sie
> programmieren.
Erfahrene Programmierer können in verschiedenen Sprachen schreiben, 
kennen aber auch die gewissen Vorteile gewisser Sprachen und bevorzugen 
daher diese. Die meisten Programmierer, die die Vorteile von C++ 
wirklich kennen (und verstehen...) würden nicht C verwenden, auch wenn 
sie es können.

Ist denn nicht auch das Hauptproblem an
1
PORTB.B0 =1; // Daten Leitung 1
2
PORTB.B1 = 0; // Daten Leitung 2
3
PORTB.B3 = 1; // Takt Leitung
dass der Compiler nicht weiß welche der Anweisungen nacheinander und 
welche gleichzeitig ausgeführt werden müssen/dürfen, und somit nicht 
richtig optimieren kann? Die ersten beiden Anweisungen könnten zu einem 
einzelnen Portzugriff optimiert werden, die letzten beiden aber nicht, 
aber das weiß der Compiler nicht. In C mit volatile Bitfields wird hier 
einfach gar nichts optimiert, aber das ist auch schlecht. DAS ist der 
Vorteil der "umständlichen" Schreibweise mit Bitmasken, dass man die 
ersten beiden Anweisugen zusammenfassen kann, weil man selber weiß, dass 
es hier geht. Wie handhabt das den Bascom?

von Markus F. (mfro)


Lesenswert?

Stefan Us schrieb:
> Ich habe noch kein Projekt gesehen, das wegen der falschen Sprache
> gescheitert ist.

Dem würde ich zustimmen. Mit einer Ausnahme: ich habe noch kein 
Java-Programm gesehen, das auch nur ansatzweise was taugen würde.

von Dr. Sommer (Gast)


Lesenswert?

Markus F. schrieb:
> ich habe noch kein Java-Programm gesehen, das auch nur ansatzweise was
> taugen würde.
Macht Sinn, denn vielen Java Anwendungen sieht man nicht an, dass sie 
Java sind. Viele Websiten basieren zB serverseitig auf Java, da sieht 
man nix von. Es soll gerüchteweise ansatzweise brauchbare 
Android-Anwendungen geben. Manche finden die Java Anwendung eclipse so 
toll, dass sie viel Geld dafür ausgeben (in Form von zB Atollic True 
Studio). Vom Code Generator STM32CubeMx sind auch einige begeistert. Und 
es gibt natürlich auch ansatzweise brauchbare normale PC Java 
Anwendungen wie yEd.

Aber das ist natürlich alles nur Beweis per Anekdote. Java ist eine sehr 
gut nutzbare Sprache mit vielen Vorteilen gegenüber Bascom, C, C++. 
Allerdings gilt natürlich wie immer, dass es für jede Sprache schlechte 
Programmierer und Programme gibt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus F. schrieb:
> ich habe noch kein Java-Programm gesehen, das auch nur ansatzweise was
> taugen würde.

Du benutzt nicht zufällig ein Android-Handy? ;-)

von Markus F. (mfro)


Lesenswert?

Jörg Wunsch schrieb:
> Du benutzt nicht zufällig ein Android-Handy? ;-)

Nö. Fällt mir nicht im Traum ein. Mein Handy läuft auf QNX.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Ist denn nicht auch das Hauptproblem an
>
1
PORTB.B0 =1; // Daten Leitung 1
2
> PORTB.B1 = 0; // Daten Leitung 2
3
> PORTB.B3 = 1; // Takt Leitung
> dass der Compiler nicht weiß welche der Anweisungen nacheinander und
> welche gleichzeitig ausgeführt werden müssen/dürfen,

doch, weiß er:  Da PORTB volatile ist sind die einzelnen Anweisungen 
keinesfalls gegeneinander zu optimieren — abgesehen vom den für .B0 und 
.B1 evtl. gemeinsam benötigten Konstanten.

Wenn das Zeugs nicht volatile ist, kann zwar optimiert werden, aber 
fehlendes volatile ist bestimmt nicht im Sinne des Erfinders ;-)

> richtig optimieren kann? Die ersten beiden Anweisungen könnten zu
> einem einzelnen Portzugriff optimiert werden, die letzten beiden
> aber nicht,

Wenn man das wirklich *WIRKLICH* will, dann muss das eben explizit 
hingeschrieben werden (z.B. via old-school Maskierung).  volatile ist 
nun mal volatile, und das gilt selbst für C++.

> aber das weiß der Compiler nicht.

Doch.  Er weiß — bzw. der Standard sagt, dass es nicht zu optimieren 
ist.

von Stefan F. (Gast)


Lesenswert?

@Markus

Fachlich hast du damit sicher Recht. Ich denke, Dr. Sommer wollte jedoch 
hervorheben, dass diese Syntax zu schlecht optimiertem Code führt, wenn 
man keine besonderen Klimmzüge drumherum baut.

Dass er damit Recht hat, konnten wir gestern oder vorgestern erst in 
einem anderen Thread lesen. Dort hatte nämlich jemand genau damit ein 
Problem, dass die Bits eines Ports nicht annähernd gleichzeitig gesetzt 
wurden.

@Joachim B

Ich finde deinen Ansatz sehr gut: Mit Makros definiert man sich 
sprechende Symbole, damit der Programmcode gut lesbar ist.

von Michael (Gast)


Lesenswert?

Joachim B. schrieb:
> #define MUL (CONST1 x CONST2)
>
> oder muss das der AVR zur Laufzeit rechnen?

Der Operator "x" ist in C überhaupt nicht definiert. Der GCC wird damit 
also höchst wenig anfangen können.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Michael schrieb:
> Joachim B. schrieb:
>> #define MUL (CONST1 x CONST2)
>>
>> oder muss das der AVR zur Laufzeit rechnen?
>
> Der Operator "x" ist in C überhaupt nicht definiert. Der GCC wird damit
> also höchst wenig anfangen können.

Joachim hat ja nur einen Auschnitt seines Codes gepostet.
Selbstverständlich steht davor noch irgendwo die Zeile
1
#define x *

;-)

von Joachim B. (jar)


Lesenswert?

Michael schrieb:
> Der Operator "x" ist in C überhaupt nicht definiert. Der GCC wird damit
> also höchst wenig anfangen können.

ich finde x hier aber lesbarer als * ich streite mich doch nicht hier 
mit der Darstellung in FETTSCHRIFFT

von Dr. Sommer (Gast)


Lesenswert?

Johann L. schrieb:
> doch, weiß er:  Da PORTB volatile ist sind die einzelnen Anweisungen
> keinesfalls gegeneinander zu optimieren

Ja ich weiß. Deswegen schrieb ich ja, dass alles einzelne Zugriffe 
werden, was natürlich aus der volatile Deklaration folgt. Dies ist 
sprachlich natürlich korrekt, aber u.U. nicht das was man will, nämlich 
effizient mehrere Bits auf einmal setzen.

von [c]C-Code[/c] (Gast)


Lesenswert?

Joachim B. schrieb:
> ich finde x hier aber lesbarer als * ich streite mich doch nicht hier
> mit der Darstellung in FETTSCHRIFFT
Dann pack den C-Code wie sich's gehört in die Code-Tags:
1
[c]C-Code[/c]

von Daniel A. (daniel-a)


Lesenswert?

Dr. Sommer schrieb:
> Stefan Us schrieb:
> Ist denn nicht auch das Hauptproblem an
>
1
PORTB.B0 =1; // Daten Leitung 1
2
> PORTB.B1 = 0; // Daten Leitung 2
3
> PORTB.B3 = 1; // Takt Leitung
> dass der Compiler nicht weiß welche der Anweisungen nacheinander und
> welche gleichzeitig ausgeführt werden müssen/dürfen, und somit nicht
> richtig optimieren kann?

Viel schlimmer finde ich dass der c standard den bitorder (nicht 
byteorder) nicht definiert. Somit ist diese art der verwendung von 
bitfields undefiniert. Bei meinem Webserver Projekt hat mich das 
debuggen und anschliessende entfernen der Bitfelder aufgrund einer 
unerwarteten bitorder ewigkeiten gekostet.

von Bernd K. (prof7bit)


Lesenswert?

Daniel A. schrieb:
> Viel schlimmer finde ich dass der c standard den bitorder (nicht
> byteorder) nicht definiert.

Wie sollte das funktionieren, wie hättest Du Dir sowas vorgestellt? Etwa 
so daß der C-Standard verbindlich vorschreibt daß gefälligst alles 
Little-Endian zu sein hat und somit alle Prozessorhersteller sich 
entweder daran halten oder es eben niemals einen C-Compiler dafür geben 
wird?

von (prx) A. K. (prx)


Lesenswert?

Bernd K. schrieb:
> so daß der C-Standard verbindlich vorschreibt daß gefälligst alles
> Little-Endian zu sein hat und somit alle Prozessorhersteller sich
> entweder daran halten oder es eben niemals einen C-Compiler dafür geben
> wird?

Wobei wir dann heute wohl über den Sinn und Unsinn der dann in C 
definierten middle endian byte order diskutieren würden. Denn die an der 
Verbreitung von C nicht unmassgeblich beteiligte PDP-11 war little 
endian bei Bytes und big endian bei Worten (oder umgekehrt?). ;-)

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Bernd K. schrieb:
> Wie sollte das funktionieren

Nunja, wenn bitfelder über mehrere bytes gehen bin ich damit 
einverstanden das dass compilerspezifisch ist. Aber bei sowas:
1
union y {
2
  uint8_t c;
3
  struct x {
4
    unsigned a:4;
5
    unsigned b:4;
6
  };
7
};
Wäre es doch praktisch gewesen wenn die entscheidung, ob c&0x0F nun a 
oder b ist nicht dem compiler überlassen worden wäre.

von (prx) A. K. (prx)


Lesenswert?

Daniel A. schrieb:
> Nunja, wenn bitfelder über mehrere bytes gehen bin ich damit
> einverstanden das dass compilerspezifisch ist.

> Wäre es doch praktisch gewesen wenn die entscheidung, ob c&0x0F nun a
> oder b ist nicht dem compiler überlassen worden wäre.

Das wäre ein seltsames Korsett geworden, wenn du dennoch eine Sprache so 
definieren willst, dass sie auf verschiedenster Hardware problemlos 
implementierbar ist. Zur Orientierung: In der Entstehungszeit von C 
waren auch Maschinen mit Bitbreiten von 12, 36, 48 und 60 Bits recht 
bekannt.

Nope, wenn dann konsequent oder garnicht. Wenn schon, dann sollte eine 
Sprache eine exakte Definition der Darstellung ermöglichen. Ich meine 
mich zu erinnern, dass Ada diese Feature enthält.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Daniel A. schrieb:
> Wäre es doch praktisch gewesen wenn die entscheidung, ob c&0x0F nun a
> oder b ist nicht dem compiler überlassen worden wäre.

Ja, Du hast Recht, ich war mit den Gedanken woanders. Wahrscheinlich 
wäre es schon möglich gewesen beizeiten eine unmißverständliche Regeln 
zu finden wie die Reihenfolge in Bitfeldern bei gegebener Endianness (so 
viele verschiedene gibts ja nicht) jeweils verbindlich auszusehen hat 
ohne irgendwelche Hardware zu benachteiligen. Aber der Zug ist wohl 
abgefahren.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Daniel A. (daniel-a)

>Wäre es doch praktisch gewesen wenn die entscheidung, ob c&0x0F nun a
>oder b ist nicht dem compiler überlassen worden wäre.

Ja, ist aber halt nicht so. Das Problem lässt sich aber mit 
plattformspezifischen Definitionen lösen, das wird auch im wahren leben 
so gemacht.
1
#ifdef __AVR__
2
3
union y {
4
  uint8_t c;
5
  struct x {
6
    unsigned a:4;
7
    unsigned b:4;
8
  };
9
};
10
#endif
11
12
#ifdef __WIN__
13
14
union y {
15
  uint8_t c;
16
  struct x {
17
    unsigned b:4;
18
    unsigned a:4;
19
  };
20
};
21
#endif

von Bernd K. (prof7bit)


Lesenswert?

Falk Brunner schrieb:
> #ifdef __AVR__
> #ifdef __WIN__

#ifdef _GCC_
#ifdef _CLANG_
#ifdef _KEIL_
#ifdef _IAR_
#ifdef _MSC_
#ifdef _BORLAND_
#ifdef _WATCOM_
[...]

Nein, ich glaube für Sachen die weder im C-Standard noch im jeweiligen 
ABI stehen sieht das einzig sinnvolle ifdef so aus:
1
#ifndef __IAR__
2
#error "Nein, Ihr habt gesagt IAR! Ich hab euch gewarnt, ihr wolltet es so!"
3
#endif

von Nase (Gast)


Lesenswert?

Daniel A. schrieb:
> Wäre es doch praktisch gewesen wenn die entscheidung, ob c&0x0F nun a
> oder b ist nicht dem compiler überlassen worden wäre.

Das ist aber völlig unabhängig von der Byte-Order, ob es a oder b ist. 
Es ist ganz einfach nicht erlaubt.

Aus einer union darfst du nur dasjenige Feld lesen, welches zuletzt 
beschrieben wurde.

von Bernd K. (prof7bit)


Lesenswert?

Nase schrieb:
> Es ist ganz einfach nicht erlaubt.
>
> Aus einer union darfst du nur dasjenige Feld lesen, welches zuletzt
> beschrieben wurde.

Lass das Union weg (Nebenkriegsschauplatz) und übergib stattdessen das 
struct an eine Funktion in einer lib die mit einem anderen Compiler 
gebaut wurde. Selbes Problem.

von (prx) A. K. (prx)


Lesenswert?

Bernd K. schrieb:
> Lass das Union weg (Nebenkriegsschauplatz) und übergib stattdessen das
> struct an eine Funktion in einer lib die mit einem anderen Compiler
> gebaut wurde. Selbes Problem.

Nicht wenn sich beide Compiler am gleichen ABI orientieren und das ABI 
die Anordnung von Bitfeldern definiert. Das wäre der richtige Platz 
dafür. Es spricht nichts dagegen, die Offenheit der Sprache C innerhalb 
einer ABI Umgebung einzuschränken. Zum Problem wird es dann, wenn du den 
Rahmen des ABI verlässt, z.B. bei Datenstrukturen auf Speichermedien 
oder im Netz.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

A. K. schrieb:
> und das ABI
> die Anordnung von Bitfeldern definiert.

Welches ABI tut das?

von Joachim B. (jar)


Lesenswert?

1
C-Code
 schrieb:
> Dann pack den C-Code wie sich's gehört in die Code-Tags:

mache ich immer ABER irgendwie hatte ich das schon mal versucht und 
klappt nicht immer,

TEST1
1
#if F_CPU < 96000000
2
#if defined(__AVR_ATmega1284P__)
3
  #define NS(_NS) ( (_NS * ( (F_CPU*9L/10L) / 1000000L))) / 1000
4
  #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / ((F_CPU*9L/10L) / 1000000L)
5
#else
6
  #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
7
  #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
8
#endif

TEST2
1
#define CONST1 10
2
#define CONST2 20
3
4
(CONST1 * CONST2)
5
6
oder
7
8
#define MUL (CONST1 *CONST2* 1)

nu gehts, wer weiss was vorher anders war, ich hatte schon Beispiele da 
klappte das trotz Codeansicht nicht, vermutlich wegen "" im Text


und hier verweigert das Forum auch "HTML" Code aus C Source Text.

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Bernd K. schrieb:
> Nase schrieb:
>> Es ist ganz einfach nicht erlaubt.
>>
>> Aus einer union darfst du nur dasjenige Feld lesen, welches zuletzt
>> beschrieben wurde.
>
> Lass das Union weg (Nebenkriegsschauplatz) und übergib stattdessen das
> struct an eine Funktion in einer lib die mit einem anderen Compiler
> gebaut wurde. Selbes Problem.

Oder caste eine variable x von type struct x folgendermassen *(unsigned 
char*)&x, ist auch erlaubt.

von (prx) A. K. (prx)


Lesenswert?

Bernd K. schrieb:
> Welches ABI tut das?

Keine Ahnung ob. Nur passt das da besser rein als in den C Standard.

von Rolf M. (rmagnus)


Lesenswert?

Joachim B. schrieb:
> Michael schrieb:
>> Der Operator "x" ist in C überhaupt nicht definiert. Der GCC wird damit
>> also höchst wenig anfangen können.
>
> ich finde x hier aber lesbarer als * ich streite mich doch nicht hier
> mit der Darstellung in FETTSCHRIFFT

Lesbarer oder nicht, wenn du wissen willst, was der Compiler aus einem 
bestimmten Stück Code macht, solltest du auch diesen Code hinschreiben 
und nicht irgendwas anderes.

Daniel A. schrieb:
> Viel schlimmer finde ich dass der c standard den bitorder (nicht
> byteorder) nicht definiert. Somit ist diese art der verwendung von
> bitfields undefiniert.

Ja, richtig. Bitfelder waren allerdings auch gar nicht dafür gedacht, so 
verwendet zu werden.

A. K. schrieb:
> Wobei wir dann heute wohl über den Sinn und Unsinn der dann in C
> definierten middle endian byte order diskutieren würden. Denn die an der
> Verbreitung von C nicht unmassgeblich beteiligte PDP-11 war little
> endian bei Bytes und big endian bei Worten (oder umgekehrt?). ;-)

Das ist nicht die einzige Architektur.
https://en.wikipedia.org/wiki/Middle_endian

Bernd K. schrieb:
> A. K. schrieb:
>> und das ABI
>> die Anordnung von Bitfeldern definiert.
>
> Welches ABI tut das?

Ich hab zwar noch kein ABI gelesen, aber rein logisch muß es das 
eigentlich zwingend definieren. Immerhin sind ABIs dafür da, daß man 
Code von Compilern, die das selbe ABI nutzen, zusammenlinken und dabei 
ein korrekt funktionierendes Binary erzeugen kann. Dazu muß auch 
definiert sein, wie Bitfelder implementiert sind.

Daniel A. schrieb:
> Oder caste eine variable x von type struct x folgendermassen *(unsigned
> char*)&x, ist auch erlaubt.

Streng genommen nicht. Die einzige Möglichkeit, die in C offiziell 
erlaubt ist, ist, die Daten per memcpy in ein Byte-Array zu kopieren.

von Joachim B. (jar)


Lesenswert?

Rolf Magnus schrieb:
> Lesbarer oder nicht, wenn du wissen willst, was der Compiler aus einem
> bestimmten Stück Code macht, solltest du auch diesen Code hinschreiben
> und nicht irgendwas anderes.

tut mir leid das ich dich überfordert habe, andere hatten es verstanden 
;-)

von Dr. Sommer (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Daniel A. schrieb:
>> Oder caste eine variable x von type struct x folgendermassen *(unsigned
>> char*)&x, ist auch erlaubt.
>
> Streng genommen nicht. Die einzige Möglichkeit, die in C offiziell
> erlaubt ist, ist, die Daten per memcpy in ein Byte-Array zu kopieren.
Doch, bei char Typen ist es als Ausnahme erlaubt. ((un)signed) char darf 
alles aliasen und darf keine Alignment Probleme haben. memcpy macht auch 
nichts anderes als ein char array kopieren, und das ist korrektes C(++).

von Joachim B. (jar)


Lesenswert?

Dr. Sommer schrieb:
> Doch, bei char Typen

mich nervt in allen Dialekten die gemischte Verwendung von signed und 
unsigned char.

Für mich ist ein Char immer unsigned, aber das sieht nicht jeder so.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bernd K. schrieb:
> Welches ABI tut das?

Jedes.

Die Anordnung der Bits in einem Bit-Field ist nämlich nicht undefined,
sondern implementation-defined.  Das bedeutet, dass es zwar der
konkreten Implementierung (hier also dem Compiler) überlassen ist, wie
sie es handhabt, aber sie muss die getroffene Wahl konsistent einhalten
und auch dokumentieren.

Damit kann man die IO-Register einer MCU in der entsprechenden
Headerdatei (die sowieso ABI-abhängig ist) durchaus als Bit-Fields
beschreiben.

von Rolf M. (rmagnus)


Lesenswert?

Dr. Sommer schrieb:
> Doch, bei char Typen ist es als Ausnahme erlaubt. ((un)signed) char darf
> alles aliasen und darf keine Alignment Probleme haben. memcpy macht auch
> nichts anderes als ein char array kopieren, und das ist korrektes C(++).

Stimmt. Hab nochmal genauer reingeschaut in die C99-Definition. Neuere 
hab ich nicht, aber da wird das gleich sein. Ich hatte mich auf diese 
Passage bezogen:

"The value may be copied into an object of type unsigned char [n] (e.g., 
by memcpy); the resulting set of bytes is called the object 
representation of the value. Values stored in bit-fields consist of m 
bits,
where m is the size specified for the bit-field. The object 
representation is the set of m bits the bit-field comprises in the 
addressable storage unit holding it. "

Klang für mich so, dass man die Daten immer kopieren muss und nicht 
direkt zugreifen darf. Aber wo anders steht:

"An object shall have its stored value accessed only by an lvalue 
expression that has one of the following types:
[...]
— a character type."

Das sagt es also sehr eindeutig.

Joachim B. schrieb:
> Dr. Sommer schrieb:
>> Doch, bei char Typen
>
> mich nervt in allen Dialekten die gemischte Verwendung von signed und
> unsigned char.
>
> Für mich ist ein Char immer unsigned, aber das sieht nicht jeder so.

In C ist es nicht definiert, ob er unsigned ist oder nicht. Konsistenter 
wäre signed. Letztendlich ist char auch nur ein Integer-Typ, und alle 
anderen Integer-Typen sind auch signed, wenn nichts anderes dran steht.
Für Text ist es sowieso egal. Nur wenn man es als kleinen Integer 
benutzen will, muss man explizit unsigned davor schreiben, wenn man das 
will. Müßte man bei allen anderen Integer-Typen aber auch. Lediglich 
wenn man explizit einen vorzeichenbehafteten kleinen Integer haben will, 
muß man anders als bei den anderen Typen das signed explizit davor 
schreiben.

von Joachim B. (jar)


Lesenswert?

Rolf Magnus schrieb:
> In C ist es nicht definiert, ob er unsigned ist oder nicht. Konsistenter
> wäre signed.

das hätte ich gerne begründet, ein Char welches negativ werden könnte?

Wenn man an ASCII denkt 7-bit 0-127 wäre das denkbar, aber negative 
Zeichen, da mag ich nicht mitdenken.

Ich finde es auch unlogisch wenn ich 100 Miese auf dem Konto habe das 
ich einen Hunderter rüberschieben muss um wieder auf Null zu sein.

Noch schlimmer im Bus, 5 Leute drin, 10 steigen aus und es müssen wieder 
5 rein damit der leer ist.

von (prx) A. K. (prx)


Lesenswert?

Joachim B. schrieb:
> das hätte ich gerne begründet, ein Char welches negativ werden könnte?

Konsistenter meint: ohne explizite Vorzeichenangabe alles signed.

Aus historischen Gründen sind chars ohne Angabe ziemlich oft signed, 
weil sich das bei der PDP-11 anbot und viele ASCII-Fans darin weniger 
Probleme mit der Portierung von Unix-Programmen sahen.

von Falk B. (falk)


Lesenswert?

@ Joachim B. (jar)

>> In C ist es nicht definiert, ob er unsigned ist oder nicht. Konsistenter
>> wäre signed.

Ja.

>das hätte ich gerne begründet, ein Char welches negativ werden könnte?

Hat er das nicht geschrieben?

"Letztendlich ist char auch nur ein Integer-Typ, und alle
anderen Integer-Typen sind auch signed, wenn nichts anderes dran steht."

>Wenn man an ASCII denkt 7-bit 0-127 wäre das denkbar, aber negative
>Zeichen, da mag ich nicht mitdenken.

>Ich finde es auch unlogisch wenn ich 100 Miese auf dem Konto habe das
>ich einen Hunderter rüberschieben muss um wieder auf Null zu sein.

Was ist daran unlogisch?

>Noch schlimmer im Bus, 5 Leute drin, 10 steigen aus und es müssen wieder
>5 rein damit der leer ist.

Haha!
???

von Peter D. (peda)


Lesenswert?

Rolf Magnus schrieb:
> Für Text ist es sowieso egal.

Nö.
Wenn man z.B. ASCII-Umlaute nach LCD wandeln will, muß man erst nach 
unsigned casten.
Oder wenn man ein Protokoll hat, was Text und Binärwerte enthält.

Unsigned char für Text hätte viele Fallgruben vermieden.

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:
> Unsigned char für Text hätte viele Fallgruben vermieden.

Eine ordentliche Programmiersprache zu verwenden auch. ;-)

von Real Programmer (Gast)


Lesenswert?

A. K. schrieb:
> Peter Dannegger schrieb:
>> Unsigned char für Text hätte viele Fallgruben vermieden.
>
> Eine ordentliche Programmiersprache zu verwenden auch. ;-)

Richtig. Deshalb verwenden "echte Programmierer" auch Fortran ;) .

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ein char ist nun einmal ein Zeichen, und ein Zeichen ist weder positiv
noch negativ, sondern eben einfach nur ein Zeichen.

Die Problematik mit dem signed und unsigned entsteht dadurch, dass
in C ein char implizit in ein int konvertiert werden kann. In den
meisten anderen Programmiersprachen gibt es diese Möglichkeit nicht.
Wenn man dort den Code eines Zeichens benötigt (bspw. in den von Peter
genannten Fällen), muss die Konvertierung explizit (in Basic, Pascal,
Python und Haskell bspw. mit der Funktion ord) erfolgen. Diese
Konvertierung liefert wie gewünscht eine nichtnegative Zahl. Für 8-Bit-
Integer-Werte (signed und unsigned) gibt es dort spezielle Datentypen,
die nicht char o.ä. heißen, sondern bspw. byte, Int8 oder Word8.

Auch wenn in C kein Zwang dazu besteht, ist es in meinen Augen guter
Stil, trotzdem zwischen Zeichen und 8-Bit-Integern zu unterscheiden. Das
bedeutet konkret:

- Für Zeichen wird der Typ char verwendet, für Strings entsprechend
  char [].
- Für 8-Bit-Integer wird signed char und unsigned char oder int8_t
  und uint8_t verwendet.
- Die Konvertierung eines Zeichens in ihren Zeichencode erfolgt
  explizit, d.h. mit einem Cast nach unsigned char oder uint8_t.
- Bei Strings erfolgt die Konvertierung entsprechend mit einem Cast nach
  unsigned char * oder uint8_t *.

Durch die Konvertierungen mag etwas mehr Schreibarbeit entstehen, es
wird dadurch aber – zusammen mit der Unterscheidung bei den Datentypen –
sofort klar, wo mit Texten und wo mit Zahlen hantiert wird.

von Bernd K. (prof7bit)


Lesenswert?

Jörg Wunsch schrieb:
> Bernd K. schrieb:
>> Welches ABI tut das?
>
> Jedes.

Also ich hab mal auf die Schnelle einen Blick in das ARM-32 ABI 
geworfen:
1
4.3.4 Bit-fields
2
A member of an aggregate that is a Fundamental Data Type may 
3
be subdivided into bit-fields; if there are unused
4
portions of such a member that are sufficient to start the 
5
following member at its natural alignment then the following 
6
member may use the unallocated portion. For the purposes of 
7
calculating the alignment of the aggregate the type of the 
8
member shall be the Fundamental Data Type upon which the 
9
bit-field is based¹. The layout of bit-fields within an aggregate 
10
is defined by the appropriate language binding.
11
12
_______
13
¹ The intent is to permit the C construct struct {int a:8; char b[7];} to have size 8 and alignment 4 .

Was ist: "The layout of bit-fields within an aggregate
is defined by the appropriate language binding."? Wo finde ich dieses 
Dokument?

von Rolf M. (rmagnus)


Lesenswert?

Joachim B. schrieb:
> Rolf Magnus schrieb:
>> In C ist es nicht definiert, ob er unsigned ist oder nicht. Konsistenter
>> wäre signed.
>
> das hätte ich gerne begründet, ein Char welches negativ werden könnte?
>
> Wenn man an ASCII denkt 7-bit 0-127 wäre das denkbar, aber negative
> Zeichen, da mag ich nicht mitdenken.

Und positive Zeichen sind für dich logischer? Ich denke dabei nicht an 
ASCII. Ich denke einfach daran, daß es Text ist, und Text ist weder 
vorzeichenbehaftet, noch vorzeichenlos. Das ganze Konzept ergibt für 
Text überhaupt keinen Sinn. Nun haben Prozessoren aber intern in der 
Regel keinen eigenen Datentyp für Text. Man behilft sich daher mit einem 
Integer-Typ, um die einzelnen Zeichen eines Strings zu speichern. Wie 
dieser interne Integer-Typ aussieht, kann mir dabei aber eigentlich egal 
sein, da ich ihn eh nicht zum Rechnen benutze, sondern nur um die Daten 
zu speichern.

> Ich finde es auch unlogisch wenn ich 100 Miese auf dem Konto habe das
> ich einen Hunderter rüberschieben muss um wieder auf Null zu sein.

Nunja, wenn du mit negativen Zahlen ganz allgemein auf Kriegsfuß stehst, 
ist das aber eine andere Sache.

Peter Dannegger schrieb:
> Rolf Magnus schrieb:
>> Für Text ist es sowieso egal.
>
> Nö.
> Wenn man z.B. ASCII-Umlaute nach LCD wandeln will, muß man erst nach
> unsigned casten.

Ja. Diesen Cast macht man an genau einer Stelle, nämlich da, wo es an 
die Hardware übergeben wird.

> Unsigned char für Text hätte viele Fallgruben vermieden.

Was Fallgruben vermieden hätte, wäre, wenn man die Trennung zwischen 
Typen für Text und Typen zum Rechnen sauber durchgezogen hätte, wie es 
bei einigen (den meisten?) anderen Sprachen der Fall ist.
Beispiel Pascal. Da kann man mit char nicht rechnen, sondern nur Text 
speichern. Es gibt aber auch noch einen Typ byte, mit dem man rechnen 
kann, den man dafür aber nicht für Text verwenden kann. Es gibt aber 
Möglichkeiten, zwischen den beiden zu konvertieren. So sieht man im Code 
auch immer ganz klar und sauber, wofür eine Variable gedacht ist.
Siehe z.B. http://wiki.freepascal.org/Char
Da interessiert sich dann auch keiner mehr dafür, ob bei char der 
darunterliegende Integer nun mit oder ohne Vorzeichen ist, weil man gar 
keine Möglichkeit hat, das überhaupt zu erkennen.

von Bernd K. (prof7bit)


Lesenswert?

Bernd K. schrieb:
> Was ist: "The layout of bit-fields within an aggregate
> is defined by the appropriate language binding."? Wo finde ich dieses
> Dokument?

Sorry, habs gefunden. Selbes Dokument Kapitel 7, (Am Beispiel ARM32, 
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf 
dieses Kapitel hab ich anfangs übersehen, andere Architekturen bin ich 
jetzt zu faul zu suchen).

Also ist es tatsächlich bis aufs letzte i-Tüpfelchen genau definiert. 
Das allzuschnelle "ist aber undefined!!!elf" das manche Kollegen immer 
wie aus der Pistole geschossen verkünden bei solchen Themen (genauso wie 
die Sache mit den Unions) ist also vollkommen überzogen wenn nicht gar 
unangebracht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, du musst unterscheiden zwischen Dingen wie hier (bei denen du
innerhalb einer MCU-Familie und dort innerhalb eines ABIs bleibst)
und allgemeingültiger Portabilität über viele verschiedene Maschinen.

Letzteres wäre bspw. ein Anwendungsfall, wenn man das SCSI-Protokoll
maschinenunabhängig implementieren will (wie es ja bspw. auch bei
USB mass storage devices benutzt wird).  Das geht halt mit
Bit-Fields nicht „aus der Dose raus“.  Entweder musst du durch ein
configure (etc.) feststellen lassen, wie die Details der konkreten
Implementierung tatsächlich aussehen, oder aber du implementierst
es eben gleich ohne Bit-Felder (mit klassischen Bitmasken).  Meist
macht man dann letzteres.

von Joachim B. (jar)


Lesenswert?

Rolf Magnus schrieb:
> Und positive Zeichen sind für dich logischer?

ja, 0-255 wie in der erweiterten (PC ASCII Tabelle)

Rolf Magnus schrieb:
> Nunja, wenn du mit negativen Zahlen ganz allgemein auf Kriegsfuß stehst,
> ist das aber eine andere Sache.

jau, seit ich nur noch (in) positiv (e) (Kontostände) denke gehts 
mir besser,
da juckt es mich auch nicht das ich als Bürger rechnerisch 
(Staats)Schulden hätte oder habe.

von Markus F. (mfro)


Lesenswert?

Für mich ist ein char kein Zeichen, sondern ein 8-Bit integer.

Den kann man entweder als genau das oder als Index in eine ASCII- (oder 
eine beliebige andere Zeichen-) Tabelle verwenden, um damit ein 
Textzeichen zu kodieren (und genau das machen die entsprechenden 
Textausgabe-Funktionen).

Und weil's nun mal einfacher ist, diesen Tabellenindex von 0 bis 255 
laufen zu lassen anstatt von -128 bis 127, hat char (zumindest 
"intuitiv") gefälligst unsigned zu sein.

Freundlicherweise ist das auch auf den meisten Plattformen so (Power ist 
die einzige, die mir bislang untergekommen ist, die das - warum auch 
immer - anders macht).

von (prx) A. K. (prx)


Lesenswert?

Markus F. schrieb:
> Freundlicherweise ist das auch auf den meisten Plattformen so

In Linux auf x86 PC sind chars signed.

von Joachim B. (jar)


Lesenswert?

Markus F. schrieb:
> hat char (zumindest
> "intuitiv") gefälligst unsigned zu sein.

meine Rede! etwas weiter höher.

A. K. schrieb:
> In Linux auf x86 PC sind chars signed.

eben das nervt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Für mich ist ein char kein Zeichen, sondern ein 8-Bit integer.

Für diese Verwendung hat die Welt (leider erst vor reichlich 15 Jahren)
die Datentypen uint8_t und int8_t geschaffen.

Wer heutzutage immer noch “char” schreibt, wenn er einen kleinen
Integer haben will, ist einfach selbst dran schuld.

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Für diese Verwendung hat die Welt (leider erst vor reichlich 15 Jahren)
> die Datentypen uint8_t und int8_t geschaffen.
>
> Wer heutzutage immer noch “char” schreibt, wenn er einen kleinen
> Integer haben will, ist einfach selbst dran schuld.

ach echt?


und wenn ich eine Var uint8_t txt[] oder unsigned char nenne und strcmp 
oder strcpy nutzen will muss ich fast immer casten, gefühlt ist sich 
nicht mal der gcc (AVR Studio, LCC32, Arduino) einig wann was gilt. Klar 
gibts für alles ne Lösung aber trotzdem nerven Fehlermeldungen bezüglich 
signed und unsigned.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> wenn ich eine Var uint8_t txt[] oder unsigned char nenne und strcmp oder
> strcpy nutzen will muss ich fast immer casten

Willst du nun kleine Ganzzahlen haben (uint8_t / int8_t) oder Zeichen
(strcmp / strcpy)?  Da solltest du dir schon mal einig werden.

Normalerweise gibt es zwischen beiden eine Import- und eine
Export-Schnittstelle, beispielsweise zwischen dem Datenregister der
UART (oftmals uint8_t) und der internen Zeichendarstellung (char).
An dieser Stelle gehört der Typecast hin, und nicht wild kreuz und
quer durch den Code.

Alle meckern hier über C, aber dass man eben zwischen Ganzzahlen und
Zeichen sauber trennen muss statt rumzuschlampen, dass wollen die
Meckerer dann auch wieder nicht wahrhaben … wie oben schon geschrieben
wurde, alle anderen Sprachen trennen sauber zwischen den beiden und
erzwingen einen geordneten Übergang (chr() / ord() etc.).

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Alle meckern hier über C, aber dass man eben zwischen Ganzzahlen und
> Zeichen sauber trennen muss statt rumzuschlampen,

ich meckere nicht, du verstehst offensichlich mein Problem nicht, macht 
aber nix.

Jetzt habe ich einen Grund zum meckern.....(vielleicht liegts am java, 
vieleicht am Preprozessor

mytools.h
1
#ifdef DEBUG
2
  #define DEBUG_PRINT(x)              Serial.print(x)
3
  #define DEBUG_PRINT_DEC_HEX(x, y)   Serial.print(x, y)
4
  #define DEBUG_PRINTLN(x)            Serial.println(x)
5
  #define DEBUG_PRINTLN_DEC_HEX(x, y) Serial.println(x, y)
6
#else
7
  #define DEBUG_PRINT(x)
8
  #define DEBUG_PRINT_DEC_HEX(x, y)
9
  #define DEBUG_PRINTLN(x)
10
  #define DEBUG_PRINTLN_DEC_HEX(x, y)
11
#endif

my_proggi.ino
das hier funzt nicht:
1
      (i2c_test_flags&(1<<RTC_3231)) ? DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt")) : DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"));

setup.ino: In function 'void setup()':
setup:250: error: expected primary-expression before ';' token

mir ist schon klar warum, nervt trotzdem :-)

Lösung oder gibts ne bessere?
1
      #ifdef DEBUG
2
      (i2c_test_flags&(1<<RTC_3231)) ? Serial.println(F(" DS3231 RTC ist gestellt")) : Serial.println(F(" DS1307 RTC ist gestellt"));
3
      #endif

ich gebe ja zu das ich kein Infomatiker oder genialer Progger bin.

: Bearbeitet durch User
von Uwe S. (de0508)


Lesenswert?

Hallo Joachim,

packe mal dein Code aus den define in diesen Block
1
#ifdef DEBUG
2
# define func(x) do { foo(x); } while (0)
3
#else
4
# define func(x) do { } while (0)
5
#endif

und berichte bitte.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:

> ich meckere nicht, du verstehst offensichlich mein Problem nicht, …

Dein Problem scheint mir zu sein, dass du [u]int8_t auch dann
benutzt, wenn es eben char sein müsste.

Ein Array voller Bytes (uint8_t) übergibt man nicht an strcmp(),
das hat keinen Sinn.  Ist das Array aber voller Text, dann sollte
es eben auch als "char" deklariert sein.

> Lösung oder gibts ne bessere?

Schwierig.  Normalerweise könnte man sich mit einem do{}while(0)
behelfen als Makroerweiterung im nicht-DEBUG-Fall, aber im Falle des
Fragezeichenoperators geht das natürlich nicht, denn der erwartet ja
keine Anweisungen, sondern Ausdrücke.   Hier wiederum würde es
genügen, im nicht-DEBUG-Fall den Makro einfach zu 0 zu erweitern, aber
das passt natürlich an vielen anderen Stellen nicht.

Ist ein arger Fall von Missbrauch des ternären Operators. ;-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Warum benutzt du den ?:-Operator, wenn dich die Rückgabewerte der 
Operanden gar nicht interessieren? Schreib stattdessen ganz klassisch 
einfach eine If-Else-Anweisung:
1
  if (i2c_test_flags&(1<<RTC_3231)) 
2
    DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt"));
3
  else
4
    DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"));

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Aber auch hier muss er in der Makro-Ersetzung den do{}while(0)-Trick
benutzen:
1
   #define DEBUG_PRINT(x) do { } while (0)

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Dein Problem scheint mir zu sein, dass du [u]int8_t auch dann
> benutzt, wenn es eben char sein müsste.
>
> Ein Array voller Bytes (uint8_t) übergibt man nicht an strcmp(),
> das hat keinen Sinn.  Ist das Array aber voller Text, dann sollte
> es eben auch als "char" deklariert sein.

vieleicht habe ich mich verschrieben,

Tatsache bleibt, das ich bei Text und LIB Funktionen ab und an mit den 
Definitionen zusammen rassel

Ich definiere Text (für mich logisch) unsigned char, die Funktionen 
erwarten ein char.

Anderes Beispiel:
Ich verwende ein Array
char text[41];
und die Var ist für mich ein Pointer auf erste Element

text -> (char *)&text[0]

manchmal klappt strcpy(neu, text);

manchmal meckert der Compiler und es klappt nur mit:

strcpy(neu, (char *)text);

weil text ein Array of char ist und kein Pointer

beobachte ich gerade einen Wandel oder warum ist das so?

Klar bemühe ich mich sauber zu programmieren, klappt nicht immer, aber 
immer Array of char zu Pointer casten ist auch irgendie 
Zeitverschwendung.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:

> Ich definiere Text (für mich logisch) unsigned char, die Funktionen
> erwarten ein char.

Diese deine Logik ist eben die Unlogik: Text solltest du als “char”
deklarieren, ganz ohne “signed” oder “unsigned”.

Text ist alles das, bei dem man mit den Elementen nichts rechnen
will, also eben das beliebte "Hello, world!", das Ergebnis eines
sprintf(buf, "Die Zahl ist %d", 42) etc. pp.  Der konkrete Datentyp,
in den die einzelnen Zeichen hier verpackt werden, interessiert
eigentlich den Programmierer gar nicht; die entsprechenden Objekte
müssen halt nur groß genug sein, die gewünschten Zeichen aufzunehmen
und durch die Bibliotheksfunktionen durchzuschieben.

Da man mit den Textelementen nichts rechnet, ist es auch völlig
schnuppe, ob sie nun als Ganzzahlen eine Vorzeicheninterpretation
hätten oder nicht.

> manchmal meckert der Compiler und es klappt nur mit:
>
> strcpy(neu, (char *)text);

Das möchte ich als konkreten Fall (in einem separaten Thread) sehen.

So, wie du es geschrieben hast, gibt es keinen Grund für den Cast.

> weil text ein Array of char ist und kein Pointer

Felder und Zeiger sind natürlich nicht identisch, aber ein Feld wird,
wenn man es irgendwo in einem Ausdruck oder als Argument einer
Funktion benutzt, stets implizit in einen Zeiger gewandelt.

Der wesentliche Unterschied ist dabei immer: wo wird der Speicher
alloziert?  Ein Zeiger alloziert keinen, sondern zeigt nur auf etwas,
für das jemand anders schon Speicher bereitgestellt haben muss.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Jörg Wunsch schrieb:
> Aber auch hier muss er in der Makro-Ersetzung den do{}while(0)-Trick
> benutzen:
>    #define DEBUG_PRINT(x) do { } while (0)

Nicht unbedingt. Den Do-While-Trick braucht man nur für function-like
Makros, die eine Sequenz mehrerer Anweisungen enthalten, in diesem Fall
also überhaupt nicht.

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stimmt, eine leere Anweisung (nur ein Semikolon) in den beiden Zweigen
der if-Anweisung sollte natürlich zulässig sein.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@ Yalu X. (yalu) (Moderator)

>einfach eine If-Else-Anweisung:

Eben. Aber auch wenn es korrektes C ist, würde ich JEDEM empfehlen, 
IMMER Klammern zu setzen.
1
  if (i2c_test_flags&(1<<RTC_3231)) {
2
    DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt"));
3
  } else {
4
    DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"));
5
  }

Warum? Die Leute von ID-Software (DOOM & Co) machen das auch so, also 
muss was dran sein ;-)
Im Ernst, damit ist die Gefahr deutlich kleiner, sich ins Knie zu 
schießen, weil man DENKT; eine nachfolgende Anweisung wäre noch im if() 
Zweig drin. Ausserdem lässt sich der Code leichter lesen und problemlos 
um weitere Anweisungen erweitern.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Die Leute von ID-Software (DOOM & Co) machen das auch so, also muss was
> dran sein

Wobei deren Coding Styleguide schon eher ungewöhnlich ist.  TABs
meidet man aufgrund der weitreichenden Differenzen, ob sie nun für
8 Zeichenpositionen (klassischer DEC-Terminal-Standard) oder nur für
4 (typischer Windows-Default) stehen, am besten komplett.  Seit die
Editoren das Ein- und Ausrücken übernehmen (also seit 25 Jahren, wenn
man Emacs nutzt :) ist das keine Bequemlichkeitseinbuße mehr, und das
bisschen mehr Platz macht das Kraut auch nicht fett.

Die meisten Styleguides, die ich kenne, empfehlen auch nicht so viele
Leerzeichen bei Klammerung, sondern halten sich eher an das natürliche
Schriftbild, wie man es auch im Textsatz nutzen würde:
1
a + (b * c);

Ich gebe zu, dass ich bei kurzen, überschaubaren if-Anweisungen schon
auch mal ohne Klammern arbeite:
1
  if (foo)
2
    print("Foo!");
3
  else
4
    do_nonfoo_action();

aber ich kann auch mit Umgebungen leben, in denen der Styleguide
stets geschweifte Klammern zu sehen wünscht. ;-)

: Bearbeitet durch Moderator
von Joachim B. (jar)


Lesenswert?

Falk Brunner schrieb:
> if (i2c_test_flags&(1<<RTC_3231)) {
>     DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt"));
>   } else {
>     DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"));
>   }

ja is klar, aber ob Klammer oder nicht, ich wette folgendes wird auch 
nicht funktionieren, aber aus anderen Gründen:
1
(i2c_test_flags&(1<<RTC_3231)) ? {DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt"))} : {DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"))};

hattest du dir überhaupt mal die Fehlermeldung angesehen?

setup.ino: In function 'void setup()':
setup:250: error: expected primary-expression before ';' token


der vermisst im ? das erste ;

Ich denke ich habe wenig Ahnung von Programmierung, du doch so viel 
mehr:
Beitrag "Re: Arduino zu empfehlen?"

aber egal da du so gut bist in Programmieren teste ich das mal:

klappt wie ich dachte nicht!

setup.ino: In function 'void setup()':
setup:208: error: expected primary-expression before '{' token
setup:208: error: expected `:' before '{' token
setup:208: error: expected primary-expression before '{' token
setup:208: error: expected `;' before '{' token
setup:454: error: expected `}' at end of input
setup:454: error: expected `}' at end of input
setup:454: error: expected `}' at end of input
setup:454: error: expected `}' at end of input

wer ist nun der Schuldige?

java oder der preprozessor?

würde der Preprozessor einfach nur seine Aufgabe erledigen gäbe es kein 
Problem sondern ne reine Textersetzung, ich tippe auf die doofe Arduino 
IDE, wie schrieb ein Mod hier mal, er habe noch keine funktionierende 
Java Anwendung gesehen.

von Falk B. (falk)


Lesenswert?

@Joachim B. (jar)

>hattest du dir überhaupt mal die Fehlermeldung angesehen?

Sicher. Aber ich muss doch nicht auf jeden Beitrag antworten.

>setup.ino: In function 'void setup()':
>setup:250: error: expected primary-expression before ';' token

>der vermisst im ? das erste ;

Nö, einen primären Ausdruck VOR dem ;

>Ich denke ich habe wenig Ahnung von Programmierung,

Ja, wenig.

> du doch so viel
>mehr:
>Beitrag "Re: Arduino zu empfehlen?"

;-)

>aber egal da du so gut bist in Programmieren teste ich das mal:

Dazu bräuchte man mal den VOLLSTÄNDIGEN Quelltext.
Deine Fragmente allein nützen rein gar nichts.

>wer ist nun der Schuldige?

Zu 99% das Wesen vor der Tastatur ;-)

>java oder der preprozessor?

Weder noch.

>würde der Preprozessor einfach nur seine Aufgabe erledigen gäbe es kein

Tut er. Dort steckt der normale, aktuelle avr gcc drunter.

>Problem sondern ne reine Textersetzung, ich tippe auf die doofe Arduino
>IDE,

Nö, die ruft nur den avr gcc auf, am Quelltext macht die rein gar 
nichts.

> wie schrieb ein Mod hier mal, er habe noch keine funktionierende
>Java Anwendung gesehen.

Jaja, all doof ausser mir.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> ob Klammer oder nicht

Es ging in den Ausführungen über die geschweiften Klammern um eine
if-Anweisung, nicht um deinen Missbrauch des ternären Operators.

Der ternäre Operator ist ja zuweilen wirklich sinnvoll, aber er
wird eben innerhalb eines Ausdrucks benutzt, um einen Wert zu
ermitteln.  Deine print-Anweisungen ermitteln aber gar keine Werte,
sondern du willst damit ja eine Aktion ausführen lassen.

Was er ganz gewiss nicht ist, ist ein allgemeiner Ersatz für die
if-Anweisung.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> wie schrieb ein Mod hier mal, er habe noch keine funktionierende Java
> Anwendung gesehen.

Das war übrigens kein Moderator, sondern Markus F.

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Es ging in den Ausführungen über die geschweiften Klammern um eine
> if-Anweisung, nicht um deinen Missbrauch des ternären Operators.

bei #define DEBUG funktioniert, dann ist das klar

ohne #define DEBUG bleibt nicht mehr viel von
1
(i2c_test_flags&(1<<RTC_3231)) ? Serial.println(F(" DS3231 RTC ")) : Serial.println(F(" DS1307 RTC "));

übrig
1
(i2c_test_flags&(1<<RTC_3231)) ?  : ;

nun ist mir wieder was klarer geworden

Klammer hin oder her.

habt Nachsicht, bin eingerostet.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> bin eingerostet

'n Tropfen Öl hilft manchmal Wunder. :-))

Manchmal ist es übrigens hilfreich, sich die Ausgabe nach dem
Präprozessing anzusehen.  Das geht, indem man (bei sonst gleichen
-D- und -I-Optionen) dem Compiler ein -E statt des -c mit auf den
Weg gibt, und ggf. nach -o eine andere Ausgabedatei benennt.  Wenn
du in der Arduino-IDE irgendwie an die Compiler-Kommandozeile
rankommst, die er live ausführt, copy&paste in ein Terminalfenster,
dort dann die Zeile entsprechend editieren und ausführen.

von Markus F. (mfro)


Lesenswert?

Jörg Wunsch schrieb:
> kein Moderator, sondern Markus F.

ich bin kein Mod, hab' aber trotzdem eine Java-Allergie.

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Wenn
> du in der Arduino-IDE irgendwie an die Compiler-Kommandozeile
> rankommst,

puh, andere Baustelle, ich bin ja schon froh das ich in der IDE die LST 
und HEX gefunden hatte (das läuft i.d.R hinterm Rücken des Users ab, 
aber ich muss mir ab und an den verbrauchten RAM ansehen um ungefähr 
abzuschätzen ob ich zuviel belegt habe und nix mehr für den Stack 
überbleibt.)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Stimmt, eine leere Anweisung (nur ein Semikolon) in den beiden Zweigen
> der if-Anweisung sollte natürlich zulässig sein.

...werden aber teilweise angewarnt.  Also doch do/while oder (void)0.

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Der ternäre Operator ist ja zuweilen wirklich sinnvoll,

Jörg Wunsch schrieb:
> Was er ganz gewiss nicht ist, ist ein allgemeiner Ersatz für die
> if-Anweisung.

ist aber auch schön einzeilig :-)

ich mag den, kurz und lesbar, aber wie wir heute sahen auch ein 
Fallstrick.

von Daniel A. (daniel-a)


Lesenswert?

Nur um eine weitere alternative zu if/else und ternärem Operator zu 
präsentieren:
1
(void)( ( bedingung ) && (( wennWahr ),1) || (( wennFalsch ),0) )

Damit währe die schlimmste variante wohl gefunden.

von Bernd K. (prof7bit)


Lesenswert?

Daniel A. schrieb:
> Damit währe die schlimmste variante wohl gefunden.

Das kannst Du laut sagen [schüttel].

von Falk B. (falk)


Lesenswert?

Wie man Probleme mit dem ? Operator löst, die man ohne ihn nie hätte . . 
.

von Joachim B. (jar)


Lesenswert?

Daniel A. schrieb:
> Damit währe die schlimmste variante wohl gefunden.

danke muss ich nicht haben.

Falk Brunner schrieb:
> Wie man Probleme mit dem ? Operator löst, die man ohne ihn nie hätte . .

stimmt, ich finde den nun m.E. trotzdem gut.

diese if else Konstrukte für mögliche Einzeiler nerven mich halt.

Immer dran denken, jeder Jeck ist anders.

da gruselt mich das eher:
Beitrag "Wie die Adresse einer "#define - Konstanten" ermitteln?"

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Joachim B. schrieb:
> diese if else Konstrukte für mögliche Einzeiler nerven mich halt.

Es steht dir frei, auch eine If-Else-Anweisung in eine einzelne Zeile zu
schreiben. Ich persönlich würde das aber nicht tun. Ebenso würde ich
deinem Rattenschwanz
1
      (i2c_test_flags&(1<<RTC_3231)) ? DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt")) : DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"));

durch zwei Umbrüche etwas mehr Struktur geben:
1
      (i2c_test_flags&(1<<RTC_3231))
2
        ? DEBUG_PRINTLN(F(" DS3231 RTC ist gestellt"))
3
        : DEBUG_PRINTLN(F(" DS1307 RTC ist gestellt"));

wenn es denn unbedingt der ?:-Operator sein muss.

Zur Verwendung diese Operators schließe ich mich der Aussage von Jörg
an:

Jörg Wunsch schrieb:
> Der ternäre Operator ist ja zuweilen wirklich sinnvoll, aber er
> wird eben innerhalb eines Ausdrucks benutzt, um einen Wert zu
> ermitteln.

Ich benutze ihn auch nur für kurze Teilausdrücke in den beiden Zweigen
und auch nur für Ausdrücke ohne Nebeneffekte. Dein obiges Beispiel
verletzt gleich alle drei dieser Bedingungen, ist also für mich eine
ganz klare Anwendung des If-Else-Konstrukts, obwohl ich sonst auch eher
ein "Zeilensparer" bin.

Aber da hat natürlich jeder seinen eigenen Geschmack :)

von Rolf M. (rmagnus)


Lesenswert?

Joachim B. schrieb:
> vieleicht habe ich mich verschrieben,
>
> Tatsache bleibt, das ich bei Text und LIB Funktionen ab und an mit den
> Definitionen zusammen rassel
>
> Ich definiere Text (für mich logisch) unsigned char, die Funktionen erwarten ein 
char.

Also mit anderen Worten: char ist dafür vorgesehen, aber du nimmst 
stattdessen lieber unsigned char und regst dich dann darüber auf, daß du 
überall nach char casten mußt. Das ist dann das, was für mich unlogisch 
klingt. Ist ungefähr so, als ob ich mit dem Auto immer nur rückwärts 
fahre und mich dann über dieses beschwere, weil es so langsam ist und 
ich davon immer Nackenschmerzen bekomme.
Ich hab's aber durchaus schon öfters gesehen, daß Leute der Meinung 
sind, Text sei eine vorzeichenlose Zahl. Ist es aber nicht. Es ist 
Text, und mit Text rechnet man nicht, PUNKT
Die Regel wurde schon genannt und ist doch eigentlich ganz einfach. Ich 
verstehe nicht, warum so viele damit nicht klar kommen:

char ist für Text.
[un]signed char ist für kleine Integer.
Bei der Übergabe von Zeichen an eine low-level-Funktion oder ein 
HW-Register muß ggf. konvertiert werden.

Und das ist alles. Wenn man das beachtet, hat man mit char überhaupt 
kein Problem.

> Anderes Beispiel:
> Ich verwende ein Array
> char text[41];
> und die Var ist für mich ein Pointer auf erste Element
>
> text -> (char *)&text[0]
>
> manchmal klappt strcpy(neu, text);
>
> manchmal meckert der Compiler und es klappt nur mit:
>
> strcpy(neu, (char *)text);
>
> weil text ein Array of char ist und kein Pointer
>
> beobachte ich gerade einen Wandel oder warum ist das so?

Warum das bei dir so ist, weiß ich nicht. Ein Array kann praktisch immer 
wie ein Zeiger auf sein erstes Element verwendet werden. Der Code ist 
ohne Cast vollkommen korrekt, also wird dein Beispiel nicht dem echten 
Code entsprechen, gegen den der Compiler was hatte.

von Peter D. (peda)


Lesenswert?

Ich finds schon komisch, was daran denn so schwer zu verstehen ist, daß 
#define nur eine Textersetzung ist.

Wenn eine Fehlermeldung kommt, braucht man doch nur den Text direkt 
einzusetzen und schon sieht man den Fehler.

Beim for(;;) kann man die 3 Ausdrücke leer lassen.
Beim ?: müssen aber alle 3 Ausdrücke existieren.

Ein simples:
1
#ifdef DEBUG
2
  #define DEBUG_PRINT(x)              Serial.print(x)
3
#else
4
  #define DEBUG_PRINT(x)              0
5
#endif

und die Sache ist gegessen

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Peter Dannegger schrieb:
> Ein simples:

ich wusste das DU die Lösung weisst, kann ich mir ja die PN sparen, 1000 
Dank.

LG jar

PS das es eine reine Textersetzung ist wusste ich, auch das dann nur ? : 
; übrig bleibt undd damit den Fehler provoziert auch.
Auf deine Lösung bin ich nicht gekommen und ich war wohl nicht der 
einzige der nicht diese Lösung fand obwohl ja hier alle anderen besser 
proggen können als ich.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Joachim B. schrieb:
> Auf deine Lösung bin ich nicht gekommen und ich war wohl nicht der
> einzige der nicht diese Lösung fand obwohl ja hier alle anderen besser
> proggen können als ich.

Du meinst die Sache mit der 0 im #else-Zweig?

Diese Möglichkeit hat doch Jörg weiter oben schon genannt:

Jörg Wunsch schrieb:
> Hier wiederum würde es genügen, im nicht-DEBUG-Fall den Makro einfach
> zu 0 zu erweitern

: Bearbeitet durch Moderator
von Joachim B. (jar)


Lesenswert?

Yalu X. schrieb:
> Du meinst die Sache mit der 0 im #else-Zweig?
>
> Diese Möglichkeit hat doch Jörg weiter oben schon genannt:

jetzt wo du es sagst :-)

Jörg Wunsch schrieb:
> Schwierig.  Normalerweise könnte man sich mit einem do{}while(0)
> behelfen als Makroerweiterung im nicht-DEBUG-Fall, aber im Falle des
> Fragezeichenoperators geht das natürlich nicht, denn der erwartet ja
> keine Anweisungen, sondern Ausdrücke.   Hier wiederum würde es
> genügen, im nicht-DEBUG-Fall den Makro einfach zu 0 zu erweitern,

hat er aber gut versteckt und keine code Tags benutzt.

OK es sind (mindestens) 2 Progger die definitiv besser sind als ich

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wenn du jetzt aber DEBUG_PRINT außerhalb einer ?:-Fallunterscheidung
benutzt
1
  DEBUG_PRINT("Hallo");

steht da nach der Makroexpansion
1
  0;

Das ist zwar legal, aber unschön und veranlasst den Compiler zur Warnung
1
statement with no effect

sofern man die Warnungen mit -Wall aktiviert hat (was man eigentlich
immer tun sollte).

Um diese Warnung zu umgehen, könnte man die 0 noch in void casten:
1
  #define DEBUG_PRINT(x)              (void)0

Dann bekommt man aber eine Fehlermeldung, wenn man den Rückgabewert von
DEBUG_PRINT (der ja definitiv existiert) doch irgenwann einmal auswerten
möchte.

Glaub's mir: Die Fallunterscheidung mit ?: ist hier einfach fehl am
Platz. Nimm ein if-else, und alles wird gut.

von Joachim B. (jar)


Lesenswert?

Yalu X. schrieb:
> Glaub's mir: Die Fallunterscheidung mit ?: ist hier einfach fehl am
> Platz. Nimm ein if-else, und alles wird gut.

oder anders, ist schon gut weil jetzt aktuell if/else

ich dachte ich könnte zurück zu ? : ;

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.