Forum: Mikrocontroller und Digitale Elektronik Portzugriff bei AVR C leserlicher machen


von Stefan F. (Gast)


Lesenswert?

Hi,
ich möchte gerne den Zugriff auf I/O Pins gut leserlich schreiben. Ist 
der folgende Code fachlich korrekt?
1
#include <stdint.h>
2
#include <avr/io.h>
3
4
inline void writePin(volatile uint8_t* port, uint8_t bit, uint8_t value) 
5
{ 
6
    if (value>0) 
7
    {
8
        *port |= (1<<bit); 
9
    }
10
    else 
11
    {
12
        *port &= ~(1<<bit); 
13
    }
14
}
15
16
#define LED3 &PORTA,1
17
18
int main(void) {
19
    while (1)
20
    {
21
        writePin(LED3,1);
22
        writePin(LED3,0);
23
    }
24
}

Der Compiler macht daraus dies:
1
00000034 <main>:
2
  34:  d9 9a         sbi  0x1b, 1  ; 27
3
  36:  d9 98         cbi  0x1b, 1  ; 27
4
  38:  fd cf         rjmp  .-6        ; 0x34 <main>

Ich glaube, mein Ansatz ist gut, denn er wurde perfekt optimiert. In 
einem echten Projekt würde ich die #defines für die Pins in eine 
separate Header Datei schreiben.

Was haltet ihr davon?

von laie (Gast)


Lesenswert?

Der Name writePin ist schlecht gewählt weil über das Portregister 
geschrieben wird.

von -.-.- (Gast)


Lesenswert?

Stefan U. schrieb:
> Ich glaube, mein Ansatz ist gut, denn er wurde perfekt optimiert. In
> einem echten Projekt würde ich die #defines für die Pins in eine
> separate Header Datei schreiben.
>
> Was haltet ihr davon?

Er wird nur in diesem einen Fall perfekt optimiert. Unter anderen 
Bedingungen (sehr viele Port-Operationen) sag ich, dass die 
Funktionssprünge bleiben, d.h. es braucht einfach länger. Warum keine 
komplett Lösung über #defines? Dann kriegst du die gleiche Effizienz, es 
halt nicht dynamisch

von Rudolph R. (rudolph)


Lesenswert?

Aber
1
PORTA |= (1<<PA1);

ist doch bereits gut lesbar. :-)

#define LED3 (1<<PA1)
PORTA |= LED3

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


Lesenswert?

Stefan U. schrieb:
1
> #define LED3 &PORTA,1
2
> 
3
> int main(void) {
4
>     while (1)
5
>     {
6
>         writePin(LED3,1);
7
>         writePin(LED3,0);
8
>     }
9
> }

> Ich glaube, mein Ansatz ist gut, denn er wurde perfekt optimiert.

Das ist nur die halbe Miete. Und auch der unwichtigere Teil.

> Was haltet ihr davon?

Nichts. Der Code ist nach wie vor schlecht lesbar. Z.B. muß man wissen, 
wie die LED angeschlossen ist. Sonst kann man nicht entscheiden ob das 
Schreiben einer 1 die LED nun an- oder ausschaltet. Und man muß auch 
wissen, welche Bedeutung die LED mit der Nummer 3 denn nun hat. Viel 
besser finde ich in diesem Zusammenhang Makros mit sprechendem Namen:
1
#define LED_error      PA1
2
#define LED_error_on   PORTA |=  (1<<LED3)
3
#define LED_error_off  PORTA &= ~(1<<LED3)

Das Makro für LED_error dient dabei nur der Bequemlichkeit - wenn ich 
die LED doch mal an einen anderen Pin verschiebe, muß ich nur dieses 
eine Makro ändern. Allerdings habe ich da nicht nur einfach "1" 
hingeschrieben, sondern "PA1" (was am Ende auch zu 1 evaluiert). Warum? 
Damit ich, wenn ich die LED doch mal an einen anderen Port verschiebe, 
daran erinnert werde mir die anderen beiden Makros anzusehen. Man kann 
das sicher mit ein bißchen mehr Breakdance noch weiter optimieren, daß 
man die LED.._on und LED.._off Makros gar nie mehr anfassen muß. 
Andererseits wird das ja eher selten passieren und man muß es mit dem 
Aufwand nicht übertreiben.

Diese ganzen hardwareabhängigen Makros landen am Ende alle in einer 
ports.h oder hal.h und werden in 99% der Fälle nie wieder angefaßt. Und 
im Code muß ich dann nie wieder nachschauen (oder nachdenken) was
1
LED_error_on()

denn nun bedeuten könnte.

von HabSelbstNullAhnung (Gast)


Lesenswert?

Axel S. schrieb:
> Nichts. Der Code ist nach wie vor schlecht lesbar.

Das fängt ja gut an, ich muss einem PIC-Hater zustimmen ;-)

von HabSelbstNullAhnung (Gast)


Lesenswert?

Oh shit, wie lange so ein "Name" im Gerät gespeichert bleibt...

Frohes Neues,
   vloki

von Fabian F. (fabian_f55)


Lesenswert?

#define set_pin_high(port,pin)  port |=  (1<<pin)
#define set_pin_low(port,pin)   port &=  ~(1<<pin)
#define toggle_pin(port,pin)    port ^=  (1<<pin)

#define LED1 PA2

Anwendung:
set_pin_high(PORTA,LED1)

usw.

von HabSelbstNullAhnung (Gast)


Lesenswert?

Fabian F. schrieb:
> usw

Warum nicht gleich so, wie Axel es vorschlägt?

von Peter D. (peda)


Lesenswert?


von Stefan F. (Gast)


Lesenswert?

> set_pin_high(PORTA,LED1)

Das gefällt mir nicht, weil ich dann wissen muss, dass LED1 an Port A 
hängt.

Genau deswegen hatte ich versucht, den Port und den Pin in eine 
Definition zu packen.

Axels bedenken, dass man wissen muss, wie die LED angeschlossen ist, 
kann ich nachvollziehen. Das halte ich für ein gute Argument für seinen 
Vorschlag, der mir gefällt:

> #define LED_error      PA1
> #define LED_error_on   PORTA |=  (1<<LED_error)
> #define LED_error_off  PORTA &= ~(1<<LED_error)

von Fabian F. (fabian_f55)


Lesenswert?

HabSelbstNullAhnung schrieb:
> Fabian F. schrieb:
>> usw
>
> Warum nicht gleich so, wie Axel es vorschlägt?

Unterschiedliche Anwendungen. Das define wie in meinem Letzten Post 
binde ich immer in jedem Projekt ein.
Das was Axel macht ist sehr Projektspezifisch und kommt daher in eine 
andere Header.

Wenn ich einen Pin häufig verwende (>4-5mal) mach ich mir eine 
Definition wie die von Axel. (SPI-Chip select, LED On Off usw.)

Wenn ich einen Pin selten ändere nutze ich die allgemeine Definition und 
schreib bestenfalls in einen Kommentar dahinter was das ist 
(CAN-Controller anable, Initialisierungen...).

von Peter D. (peda)


Lesenswert?

Stefan U. schrieb:
> Axels bedenken, dass man wissen muss, wie die LED angeschlossen ist,
> kann ich nachvollziehen.

Ich kennzeichne solche Pins mit einem führenden x, z.B.:
1
#include "sbit.h"
2
3
#define LED0 PORT_B7
4
#define xKEY1 PIN_D0  // low active
5
6
LED0 = !xKEY1;        // LED on, if key pressed

von Joachim B. (jar)


Lesenswert?

Axel S. schrieb:
> Viel
> besser finde ich in diesem Zusammenhang Makros mit sprechendem Namen:
> #define LED_error      PA1
> #define LED_error_on   PORTA |=  (1<<LED3)
> #define LED_error_off  PORTA &= ~(1<<LED3)

gefällt mir auch am Besten, genauer gesagt so mache ich es auch

auch durch die Vergabe der Namen LED_ finde ich im Code alle LED_ immer 
wieder und mit _error kann ich deren Bedeutung im Code sofort 
nachvollziehen auch nach Jahren.

LED_error_on;
LED_error_off; ist im Code selbsterklärend, was interessiert mich im 
Code wo die Led an welchem Pin angeschlossen ist?

Dafür gibt es Header welche ich mir baue mit pins.h und dort habe ich 
die Übersicht welche Pins belegt sind welche frei, welche geeignet sind 
weil nicht anders nutzbar (PWM IRQ TxD RxD INT0) und durch pins.h ist es 
auch leicht den AVR zu tauschen ohne den Code zu ändern.

von Fabian F. (fabian_f55)


Lesenswert?

Stefan U. schrieb:
>> set_pin_high(PORTA,LED1)
>
> Das gefällt mir nicht, weil ich dann wissen muss, dass LED1 an Port A
> hängt.

Wenns daran scheitert:
#define LED1 PORTA,PA2

set_pin_high(LED1);

> Genau deswegen hatte ich versucht, den Port und den Pin in eine
> Definition zu packen.
>
> Axels bedenken, dass man wissen muss, wie die LED angeschlossen ist,
> kann ich nachvollziehen.

Hat durchaus seine Existenzberechtigung solche defines zu benutzten, 
aber ich bevorzuge meistens die allgemeine Definition, weil man die 
leichter automatisieren kann:

void LED_bar(uint8 delay)
{
  for (unint8 i=0, i<8, i++)
  {
    set_pin_high(LED_ARRAY01, i);
    sleep_ms(delay);
  }
}

Anstatt:
void LED_bar(uint8 delay)
{
 LED1_on;
 sleep_ms(delay);
 LED2_on;
 sleep_ms(delay);
 LED3_on;
 sleep_ms(delay);
 LED4_on;
 sleep_ms(delay);
 LED5_on;
 sleep_ms(delay);
 LED6_on;
 sleep_ms(delay);
 LED7_on;
 sleep_ms(delay);
 LED8_on;
 sleep_ms(delay);
}

von Stefan F. (Gast)


Lesenswert?

@Peter:
Diese sbit.h kenne ich, sie wurde hier vor einigen Monaten schon einmal 
ausführlich vorgestellt.

Allerdings ist sie für meinen Geschmack zu ausgefuchst - zu groß und 
nicht leicht nachvollziehbar, wie man sie richtig anwendet.

> Wenns daran scheitert:
> #define LED1 PORTA,PA2
> set_pin_high(LED1);

Dann sind wir wieder auf meinen ersten Vorschlag zurück gekommen. Denn 
dieses Konstrukt erfordert IMHO, dass set_pin_high() eine in C 
geschriebene Funktion ist (kein Makro). Und dann muss man wissen, ob die 
LED bei High oder bei Low leuchtet.

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


Lesenswert?

Fabian F. schrieb:
> HabSelbstNullAhnung schrieb:
>> Fabian F. schrieb:
>>> usw
>>
>> Warum nicht gleich so, wie Axel es vorschlägt?
>
> Unterschiedliche Anwendungen. Das define wie in meinem Letzten Post
> binde ich immer in jedem Projekt ein.
> Das was Axel macht ist sehr Projektspezifisch und kommt daher in eine
> andere Header.

Warum sollte man unterhalb des hardwarespezifischen Makros noch eine 
Abstraktionsschicht einfügen wollen? Da dieser Krempel definitionsgemäß 
spezifisch für eine bestimmte Hardware ist, darf er auch gerne 
spezifisch für eine Architektur sein. Ich habe da überhaupt keine 
Skrupel, direkt auf Hardware-Register zuzugreifen.

Ich halte es im Gegenteil für ausgesprochenen Humbug, Abstraktionen und 
APIs aufeinander zu stapeln wie Bauklötze. Das sehe ich viel zu häufig 
(und es ist in vielen Fällen Ursache von Performanceproblemen).

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


Lesenswert?

Fabian F. schrieb:

> Hat durchaus seine Existenzberechtigung solche defines zu benutzten,
> aber ich bevorzuge meistens die allgemeine Definition, weil man die
> leichter automatisieren kann:
>
> void LED_bar(uint8 delay)
> {
>   for (unint8 i=0, i<8, i++)
>   {
>     set_pin_high(LED_ARRAY01, i);
>     sleep_ms(delay);
>   }
> }

> Anstatt:
> void LED_bar(uint8 delay)
> {
>  LED1_on;
>  sleep_ms(delay);
>  LED2_on;
>  sleep_ms(delay);
>  LED3_on;
...

Ganz schlechtes Beispiel. Wenn man 8 LED hat, die man einzeln ein- und 
ausschalten können will, dann muß man keineswegs ein Makro pro LED 
schreiben, sondern es reichen nach wie vor zwei Makros (die man im 
Anwendungscode verwendet). Makros können schließlich Parameter haben. 
Und wenn die LEDs keine individuellen Namen haben, sondern eine Nummer, 
dann paßt ein INT Parameter für die Nummer der LED ja prima.

von Ich (Gast)


Lesenswert?

Axel S. schrieb:
> besser finde ich in diesem Zusammenhang Makros mit sprechendem Namen:
1
#define LED_error      PA1
2
#define LED_error_on   PORTA |=  (1<<LED3)
3
#define LED_error_off  PORTA &= ~(1<<LED3)

Folgendes ist auch eine Möglichkeit, dann muss man nur 2 Stellen 
umschreiben:
1
#define LED_error_Pin  (PA1)
2
#define LED_error_Port (PORTA)
3
#define LED_error_on   (LED_error_Port |=  (1<<LED_error_Pin))
4
#define LED_error_off  (LED_error_Port &= ~(1<<LED_error_Pin))

Generell sollte man aber vermeiden Funktionen hinter Makros zu 
verstecken.
Gründe:
- Schlecht debugbar
- Sprache wird redefiniert (C bietet genau für sowas Funktionen)
- Fehlendes Typechecking (bei Makros mit Argumenten)
- Eventuell Nebeneffekte (Klammerung usw.)
- Autoformater in Eclipse kommt mit LED_error_on(); nicht zurecht ;) - 
macht daraus immer folgendes:
1
LED_error_on()
2
;
1
void LED_error_on(void)
2
{
3
    PORTA |=  (1<<PA1);
4
}

oder
1
void LED_error_on(void)
2
{
3
    LED_error_Port |=  (1<<LED_error_Pin);
4
}

Normalerweise sollte das auch vom Compiler in sbi und cbi umgewandelt 
werden (kann sein, dass dafür ein Compilerswitch notwendig ist). Aber 
das funktioniert nur innerhalb EINER Datei, sonst wird ein 
Funktionsaufruf daraus gemacht! Wenn du LED_error_on() dann also in der 
main.c verwendest msust du es auch in der main.c definieren und nicht in 
einer led.c oder so!

von Stefan F. (Gast)


Lesenswert?

> Aber das funktioniert nur innerhalb EINER Datei, sonst wird ein
> Funktionsaufruf daraus gemacht!

Oh, das ist ein guter Hinweis. Habe ich noch gar nicht bedacht.

von Tom (Gast)


Lesenswert?

Ich schrieb:
> Aber
> das funktioniert nur innerhalb EINER Datei, sonst wird ein
> Funktionsaufruf daraus gemacht!

Mit Link Time Optimisation nicht unbedingt.

von Peter D. (peda)


Lesenswert?

Ich schrieb:
> Aber
> das funktioniert nur innerhalb EINER Datei, sonst wird ein
> Funktionsaufruf daraus gemacht!

Wenn Funktionen geinlined werden sollen, dann sollte man das auch so 
hinschreiben. Und dann gehören sie natürlich in die *.h-Datei.
Stillschweigend vom Compiler irgendwas zu erhoffen, gehört sich nicht.

von Ich (Gast)


Lesenswert?

Peter D. schrieb:
> Ich schrieb:
>> Aber
>> das funktioniert nur innerhalb EINER Datei, sonst wird ein
>> Funktionsaufruf daraus gemacht!
>
> Wenn Funktionen geinlined werden sollen, dann sollte man das auch so
> hinschreiben. Und dann gehören sie natürlich in die *.h-Datei.
> Stillschweigend vom Compiler irgendwas zu erhoffen, gehört sich nicht.

In C gibt es kein "inline", das gibt es nur in C++, daher bleibt einem 
nichts anderes übrig. Der GCC kann das zwar aber da ist es nur ein 
Hinweis an den Compiler, der nicht zwangsweise umgesetzt wird. Verlässt 
man sich aber darauf, kann das schief gehen. Wenn die Funktion in einer 
anderen Datei definiert ist kann der Kompiler das ja ohnehin nicht 
inlinen, da die Implementierug der Funktion nicht bekannt ist.

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


Lesenswert?

Ich schrieb:
> Generell sollte man aber vermeiden Funktionen hinter Makros zu
> verstecken.

War ja klar, daß so ein Kommentar noch kommen würde. Doch, man will 
das mit einem Makro machen. Genau dafür sind die Makros da.

> Gründe:
> - Schlecht debugbar

?

> - Sprache wird redefiniert (C bietet genau für sowas Funktionen)

Und Makros.

> - Fehlendes Typechecking (bei Makros mit Argumenten)

In diesem Kontext irrelevant.

> - Eventuell Nebeneffekte (Klammerung usw.)

Kann man lernen. Zugegeben, meinen Makros fehlten die Klammern. Ich 
wollte aber auch einen ganz anderen Punkt demonstrieren: sprechende 
Namen und eine Abstraktion davon was aus Sicht des µC passiert (ein Bit 
auf 1 setzen) und was aus Anwendungssicht passiert (eine LED geht an).

> - Autoformater in Eclipse kommt mit LED_error_on(); nicht zurecht ;)

Eclipse will man ohnehin vermeiden. Bloat ohne Ende.

Und überhaupt. Wenn ein Werkzeug (in dem Fall eine IDE bzw. deren 
Editorkomponente) nicht mit dem Standard-Sprachumfang zurecht kommt, 
dann ist sie schlicht und einfach kaputt.

Leider haben viele Anfänger Angst vor Makros. Und das nicht zuletzt 
deswegen, weil "Experten" wie du ihnen diese Angst einreden.

> das funktioniert nur innerhalb EINER Datei, sonst wird ein
> Funktionsaufruf daraus gemacht! Wenn du LED_error_on() dann also in der
> main.c verwendest msust du es auch in der main.c definieren und nicht in
> einer led.c oder so!

Noch ein Punkt der für Makros spricht. Denn tatsächlich will man eine 
solche Abstraktionsschicht auslagern. Klar kann man die Funktionen dann 
static definieren und in eine zentrale Headerdatei stecken. Aber IMHO 
ist das wieder nur ein Workaround den man eigentlich gar nicht bräuchte.

von Peter D. (peda)


Lesenswert?

Ich schrieb:
> In C gibt es kein "inline"

Der GCC kann das mittels Attribut, bequemer Weise macht man das mit 
einem Macro:
1
// always inline function x
2
#define AIL(x)          static x __attribute__ ((always_inline)); static x

von avr (Gast)


Lesenswert?

Axel S. schrieb:
> Klar kann man die Funktionen dann
> static definieren und in eine zentrale Headerdatei stecken. Aber IMHO
> ist das wieder nur ein Workaround den man eigentlich gar nicht bräuchte.

Das ist kein Workaround sondern der richtige Weg. Außerdem sollte damit 
gleich eine gescheite Abstraktionsschicht aufbauen. Z.B.
static inline void SetErrorLED(uint8_t state) { ... }

Sobald in diesen Funktionen ein bisschen mehr drin steht, willst du die 
nicht in Makros kapseln. Das ist unleserlich, fehleranfällig und 
schlecht zu debuggen, weil man eben Makros nicht debuggen kann. Makros 
braucht man für solche Sachen einfach nicht. Die sind an anderen Stellen 
praktisch. Beispielsweise für komfortables Assert-Zeugs in C.

von Ich (Gast)


Lesenswert?

Axel S. schrieb:
>> - Schlecht debugbar
>
> ?

Schon mal durch ein Makro gestept?

>> - Sprache wird redefiniert (C bietet genau für sowas Funktionen)
>
> Und Makros.

Nein.

>> - Fehlendes Typechecking (bei Makros mit Argumenten)
>
> In diesem Kontext irrelevant.

Hier ja, sonst nein. Hab es der Vollständigkeit halber erwähnt.

>> - Eventuell Nebeneffekte (Klammerung usw.)
>
> Kann man lernen. Zugegeben, meinen Makros fehlten die Klammern. Ich
> wollte aber auch einen ganz anderen Punkt demonstrieren: sprechende
> Namen und eine Abstraktion davon was aus Sicht des µC passiert (ein Bit
> auf 1 setzen) und was aus Anwendungssicht passiert (eine LED geht an).

Ja, sprechende Namen sollte man verwenden. Auf der Klammerung wollte ich 
eigentlich gar nicht rumreiten aber das ist z.B. einer der Gründe warum 
bei Makros vorsicht geboten ist. Wenn du schon häufiger mit Makros zu 
tun gehabt hättest, hättest du die Klammern automatisch gesetzt, weil du 
über die Fallstricke Bescheid wüsstest.

> Eclipse will man ohnehin vermeiden. Bloat ohne Ende.

Geschmacksache. Wenn ein Tool hilfreich ist, kann man es auch verwenden. 
Ob das der Fall ist, muss jeder für sich selber entscheiden. Ich 
persönlich finde Eclipse sehr hilfreich.

> Und überhaupt. Wenn ein Werkzeug (in dem Fall eine IDE bzw. deren
> Editorkomponente) nicht mit dem Standard-Sprachumfang zurecht kommt,
> dann ist sie schlicht und einfach kaputt.

Der Autoformater ist nur eine Convenience Funktion. Man beachte auch den 
Zwinkersmiley.

> Leider haben viele Anfänger Angst vor Makros. Und das nicht zuletzt
> deswegen, weil "Experten" wie du ihnen diese Angst einreden.

Der Präprozessor ist hilfreich, man kann sich aber auch ins Knie 
schießen damit, deshalb ist hier auch eine gewisse Vorsicht geboten, das 
ist schon ok so.

>> das funktioniert nur innerhalb EINER Datei, sonst wird ein
>> Funktionsaufruf daraus gemacht! Wenn du LED_error_on() dann also in der
>> main.c verwendest msust du es auch in der main.c definieren und nicht in
>> einer led.c oder so!
>
> Noch ein Punkt der für Makros spricht. Denn tatsächlich will man eine
> solche Abstraktionsschicht auslagern. Klar kann man die Funktionen dann
> static definieren und in eine zentrale Headerdatei stecken. Aber IMHO
> ist das wieder nur ein Workaround den man eigentlich gar nicht bräuchte.

Nein, man kann es doch auslagern ohne Makros. Dein Vorschlag mit Code in 
der Headerdatei ist genau so Murks.

von Marc S. (marc_s86)


Lesenswert?

Ich schrieb:
> In C gibt es kein "inline"

Doch, seit C99

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


Lesenswert?

Ich schrieb:
> Axel S. schrieb:
>>> - Schlecht debugbar
>>
>> ?
>
> Schon mal durch ein Makro gestept?

Wieviele Steps willst du für ein Makro brauchen, das genau ein 
C-Statement lang ist?

>>> - Sprache wird redefiniert (C bietet genau für sowas Funktionen)
>>
>> Und Makros.
>
> Nein.

Aber doch.

>>> - Fehlendes Typechecking (bei Makros mit Argumenten)
>>
>> In diesem Kontext irrelevant.
>
> Hier ja, sonst nein.

Eben.

>> Leider haben viele Anfänger Angst vor Makros. Und das nicht zuletzt
>> deswegen, weil "Experten" wie du ihnen diese Angst einreden.
>
> Der Präprozessor ist hilfreich, man kann sich aber auch ins Knie
> schießen damit, deshalb ist hier auch eine gewisse Vorsicht geboten, das
> ist schon ok so.

Nur daß in dem Kontext in dem wir hier gerade sind, deine Einwände 
allesamt für die Katz sind. Das ist doch genau mein Punkt.

Kann man sich mit Makros in den Fuß schießen? Ja, man kann. Wird es 
unübersichtlich, wenn ein Makro zu 100 Zeilen C-Code expandiert und man 
den Code dann debuggen will? Ja, wird es. Ist es relevant im Rahmen 
dessen, was wir gerade diskutieren? Nein, ist es nicht.

Du darfst gerne vor Makros warnen, wenn es angebracht ist. Aber laß doch 
bitte die Kirche im Dorf. Ein Makro ohne Paramter, das zu genau einem 
Statement expandiert, soll gefährlich sein? Wer es schafft, sich damit 
in den Fuß zu schießen hat kein Problem mit Makros, der hat ein Problem 
damit, überhaupt erstmal zu laufen ...

>> Noch ein Punkt der für Makros spricht. Denn tatsächlich will man eine
>> solche Abstraktionsschicht auslagern. Klar kann man die Funktionen dann
>> static definieren und in eine zentrale Headerdatei stecken. Aber IMHO
>> ist das wieder nur ein Workaround den man eigentlich gar nicht bräuchte.
>
> Nein, man kann es doch auslagern ohne Makros. Dein Vorschlag mit Code in
> der Headerdatei ist genau so Murks.

Blöderweise braucht es der Compiler so. In C gibt es kein verbindliches 
Inlining. Wenn der Compiler sich entscheidet, die Funktion nicht zu 
inlinen, kriegst du wunderschöne duplicate symbol Fehler von Linker wenn 
du die Funktion nicht static definierst. Und mich würden derart 
duplizierte inline-gemeint aber vom Compiler dann doch lieber 
nicht-inline generierte static Funktionen schon irgendwie stören. Und 
weil wir dabei sind: noch mehr würde mich stören, wenn der Compiler 
statt des hinreichenden sbi/cbi da einen echten Call und eine Funktion 
mit zig Taken Prolog und Epilog generieren würde. Da schreibe ich dann 
doch lieber ein paar redundante Klammern in meine Makros.

Marc S. schrieb:
> Ich schrieb:
>> In C gibt es kein "inline"
>
> Doch, seit C99

Ja, aber. Ja, gibt es. Aber die Semantik ist kaputt. Hatten wir gerade 
nebenan. Man muß dann "static inline" schreiben. Sonst geht es karpott, 
wenn dem Compiler gerade danach ist.

Und das ist der Haß schlechthin. Wenn sich mein Code auf einmal 
verschieden verhält, je nachdem welche Laune der Compiler beim 
Übersetzen gerade hatte ...

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

Ich liebe Macros, insbesondere solche:

#define begin {
#define end }
#define equ ==
#define plus +
#define MACRO obfuscation

MfG Klaus

von avr (Gast)


Lesenswert?

Axel S. schrieb:
irgendwas über Makros

Ach vergiss es. Es gibt keinen einzigen Grund Makros einzusetzen. Und 
nur weil du bei deinem Spezialfall keinen Grund dagegen siehst, sind sie 
noch lange nicht besser als das entsprechende Konstrukt in C. Makros 
sind eben zu vermeiden. Gerade dann wenn sie einfach ersetzbar sind. Die 
Gründe kannst du oben nachlesen. Wie ich schon oben schrieb, finde ich 
eine SetErrorLed(uint8_t state) Funktion sauberer und da kann man eben 
wieder die Typsicherheit gebrauchen.

Übrigens: Spätestens seit LTO kann man diese Funktionen auch in normale 
C-Dateien packen und der Linker optimiert das genau so weit wie Makros 
oder eben static inline Funktionen. Viel sauberer als dein Makrozeugs.

von Sheeva P. (sheevaplug)


Angehängte Dateien:

Lesenswert?

Stefan U. schrieb:
> ich möchte gerne den Zugriff auf I/O Pins gut leserlich schreiben. Ist
> der folgende Code fachlich korrekt?
> [...]
> Was haltet ihr davon?

Ich persönlich finde dieses Mixen von #define und Funktionsaufruf nicht 
sehr elegant, weil die Funktionssignatur mit drei Parametern, der Aufruf 
jedoch mit nur zwei Parametern arbeitet. Mit C++11 (ja, ich habe Jehova 
gesagt) und einer Struktur geht das IMHO übersichtlicher:
1
#include <stdint.h>
2
#include <avr/io.h>
3
4
typedef struct {
5
  volatile uint8_t* port;
6
  uint8_t bit;
7
} portbit_t;
8
9
inline void writePin(portbit_t pb, uint8_t value) { 
10
    if (value>0) {
11
        *pb.port |= (1<<pb.bit); 
12
    } else {
13
        *pb.port &= ~(1<<pb.bit); 
14
    }
15
}
16
17
int main(void) {
18
19
  portbit_t led3{&PORTA, 1};
20
21
  while (1) {
22
    writePin(LED3, 1);
23
    writePin(LED3, 0);
24
  }
25
}

Beim Herumspielen mit Deinem Code ist mir aufgefallen, daß der gcc die 
writePin()-Funktion nur dann wegoptimiert, wenn -flto eingeschaltet ist. 
Dein Code kompiliert ohne -flto zu 158 Byte, mit zu 118 Byte. Bei meinem 
Code wird die Funktion auch ohne -flto wegoptimiert, so daß er immer zu 
118 Byte kompiliert, egal ob mit oder ohne -flto.

Außerdem haben unsere Codes einen dummen Fehler, der mir aufgefallen 
ist, als ich mit C++-Klassen für Pins und Register gespielt und bemerkt 
habe, daß der generierte Code zwei Byte größer ist als jener für: der 
Pin wird dabei nämlich gar nicht als Output gesetzt. Das macht die 
C++-Klasse für den Pin jedoch im Konstruktor automatisch und kompiliert 
daher, egal ob mit oder ohne -flto, zu denselben 120 Bytes, zu denen 
auch die vorherigen Codes kompilieren, wenn wir den Fehler beheben 
würden:
1
#include <Pin.hpp>
2
#include <Reg.hpp>
3
4
int main(void) {
5
6
  OutputPin led3( PINDEF(A, 1) );
7
8
  while(true) {
9
    led3.setHigh();
10
    led3.setLow();
11
  }
12
    
13
  return 0;
14
}

Das erscheint mir persönlich nicht nur die lesbarste, sondern auch die 
am wenigsten fehleranfällige Version zu sein -- so ein Konstruktor hat 
schon den durchaus beabsichtigten Vorteil, daß man sich um die 
Initialisierung keine großen Gedanken mehr machen muß. YMMV. ;-)

PS: Die Headerdateien "Reg.hpp" und "Pin.hpp" findest Du im Anhang. Die 
Größen wurden mit avr-size ermittelt, kompiliert wurde mit "-Os 
-mmcu=atmega32", mit und ohne "-flto" sowie für C++ mit "-std=c++11".

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Axel Schwenke (a-za-z0-9)

Ich halte es im Gegenteil für ausgesprochenen Humbug, Abstraktionen und
>APIs aufeinander zu stapeln wie Bauklötze. Das sehe ich viel zu häufig
>(und es ist in vielen Fällen Ursache von Performanceproblemen).

MEINE REDE!!!

K.I.S.S.

von Stefan F. (Gast)


Lesenswert?

Ja schön, aber jetzt sind wir bei C++, da wollte ich eigentlich nicht 
hin.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Falk B. schrieb:
> @ Axel Schwenke (a-za-z0-9)
>
> Ich halte es im Gegenteil für ausgesprochenen Humbug, Abstraktionen und
>>APIs aufeinander zu stapeln wie Bauklötze. Das sehe ich viel zu häufig
>>(und es ist in vielen Fällen Ursache von Performanceproblemen).
>
> MEINE REDE!!!
>
> K.I.S.S.

Sehe ich genauso.

Gerade die Makro-Definitionen vereinfachen das Ganze. Solche Dinge wie 
einfache Portzugriffe bleiben damit überschaubar. Probleme mit dem 
Debugger gibt es auch keine, da man solche Einzeiler, die ein Bit setzen 
oder löschen, gar nicht debuggen braucht.

Mehrere aufeinander gestapelte Abstraktionsschichten hingegen vernebeln 
einen einfachen Portzugriff derart, dass man dann tatsächlich einen 
Debugger braucht, um herauszubekommen, ob das verdammte Ding das Bit nun 
wirklich setzt oder nicht.

: Bearbeitet durch Moderator
von Sheeva P. (sheevaplug)


Lesenswert?

Stefan U. schrieb:
> Ja schön, aber jetzt sind wir bei C++, da wollte ich eigentlich nicht
> hin.

Du wolltest doch die Zugriffe leserlicher machen, und das geht mit C++ 
nun einmal ganz besonders gut. ;-)

von avr (Gast)


Lesenswert?

Frank M. schrieb:
> Mehrere aufeinander gestapelte Abstraktionsschichten hingegen vernebeln
> einen einfachen Portzugriff derart, dass man dann tatsächlich einen
> Debugger braucht, um herauszubekommen, ob das verdammte Ding das Bit nun
> wirklich setzt oder nicht.

Jaja, also du meinst tatsächlich dass ein

#define name xxx

weniger fehleranfällig ist als das:

void name(void)
{
  xxx
}

Im Übrigen hast du das Prinzip der Abstraktion nicht verstanden. Daher 
müssen wir hier gar nicht erst weiterdiskutieren. Bei mehreren 
Abstraktionsschichten kann mn kann jede Schicht einzeln für sich testen. 
Man kann sogar die unterste durch eine andere ersetzen und das ganze am 
PC testen. Aber laut dir hat das ganze ja keine Vorteile und weil man 
LTO deaktiviert, merkt man auch nicht dass es genau so schnell wie 
andere Lösungen ist.

Mir geht es um sauberes und einheitliches Softwaredesign. Und dabei 
sollten die Portzugriffe auf die gleiche Art wie andere Peripherie 
abstrahiert werden. Einheitlich bedeutet auch, dass sie keine 
Extrawürste mit Makros bekommen. Das braucht man auch gar nicht, da die 
einheitliche Lösung keine Nachteile hat. Auch keine 
Geschwindigkeitseinbußen. Der GCC kann ohne Probleme mit LTO mehrere 
Schichten zusammenfassen.

Bei kleinen Projekten kann man natürlich alles machen. Aber sobald das 
Projekt größer wird, bietet eine sauber aufgebaute Abstraktionsschicht 
eine Menge an Vorteilen.

von Peter D. (peda)


Lesenswert?

Sheeva P. schrieb:
> led3.setHigh();
>     led3.setLow();

Hier hat man aber wieder das Problem ist nun setHigh LED an oder aus?

von Stefan F. (Gast)


Lesenswert?

Naja, man kann ja statt setHigh/setLow auf setOn/setOff umstellen und 
dann zwei unterschiedliche Klassen verwenden, die das korrekt auf die HW 
umsetzen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

avr schrieb:
> Daher müssen wir hier gar nicht erst weiterdiskutieren.

Freut mich. Bin nämlich gerade nicht in Stimmung.

von Joachim B. (jar)


Lesenswert?

avr schrieb:
> #define name xxx
>
> weniger fehleranfällig ist als das:
>
> void name(void)
> {
>   xxx
> }


ich bin hin und hergerissen, beides hat seinen Charme, was besser ist 
müssen die Profiprogger entscheiden.

Frank M. schrieb:
> avr schrieb:
>> Daher müssen wir hier gar nicht erst weiterdiskutieren.
>
> Freut mich. Bin nämlich gerade nicht in Stimmung.

aber die wollen nicht.......

als ich noch "ProfiProgger" war hatte ich Projekte am DOS Rechner in C 
und habe die zu Hause auch weiterprogrammiert wenn es zu Abgabe eng 
wurde, @work auf dem PC, @home auf dem AtariST, weil aber daheim die 
Testumgebung fehlte, ein ganzer Prüfturm mit Messgeräte musste ich mir 
Dummys einfallen lassen, das ging in Unteroutinen besser als in 
#defines.

Die Unteroutinen (functions()) konnten bleiben wie sie sind, @work haben 
sie Messwerte aus dem Gerät geliefert, @home eben Dummyausgaben.

von daher würde ich > void name(void) bevorzugen und im > void 
name(void) #defines @home or NOT

LG jar

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Stefan U. schrieb:
> inline void writePin(volatile uint8_t* port, uint8_t bit, uint8_t value)

Stefan U. schrieb:
> Naja, man kann ja statt setHigh/setLow auf setOn/setOff umstellen und


Tja, wenn du deine Firmware(n) eben genau so aufbauen willst, dann mußt 
du es halt so tun - ABER: ich halte eigentlich garnichts von sowas.

Wozu sollte eigentlich eine Funktion gut sein, die aus einem fetten Satz 
Argumente heraus nix weiter tut als ein Portpin hi oder lo zu stellen? 
Das ist doch keine Hardware-Abstraktion, sondern nur eine 
Verbürokratisierung.

Mein Stil ist es eher, Funktionen zur Hardware-Abstraktion zu schreiben, 
die diesen Namen auch tatsächlich verdienen. In deren Headerfile kommt 
dann ein Portpin überhaupt nicht mehr vor.

Also nicht writePin(welches, wie, wohin)  sondern etwa sowas:
extern bool AnlasserStarten(void);
extern bool Gangeinlegen(int welcher);
extern bool InitSerial(int id_Port,long baudrate);
extern bool IsCharAvailable(int id_Port);
extern char SendChar(int id_Port, char c);

na und so weiter.

Also problembezogene Schnittstellen zum eigentlichen Hauptprogramm hin, 
damit man sich dort nicht über so niedere Dinge wie das Setzen eines 
Pins kümmern muß. Sowas macht das Ganze auch portabel, denn wenn man die 
niedrigste Treiberschicht an eine andere Architektur angepaßt hat, dann 
kann man sich auf sein eigentliches Vorhaben konzentrieren. Mit 
irgendwelchen writePin(xyz) in höheren Schichten der Firmware oder gar 
in main geht das nicht.

W.S.

von Stefan F. (Gast)


Lesenswert?

> Das ist doch keine Hardware-Abstraktion

Danach hatte ich auch gar nicht gefragt. Mir ging es darum, die Zeilen 
besser lesbar zu machen. Lies nochmal meinen initialen Beitrag.

von M. K. (sylaina)


Lesenswert?

Stefan U. schrieb:
> Danach hatte ich auch gar nicht gefragt. Mir ging es darum, die Zeilen
> besser lesbar zu machen. Lies nochmal meinen initialen Beitrag.

Warum ist denn für dich z.B.
1
PORTB |= (1 << PB1);

nicht gut lesbar? PORTB und PB1 kann man sich ja auch durch #defines 
umdefinieren? Da habe ich bisher noch keine Ambitionen verspürt hier was 
zu ändern.
1
.
2
.
3
.
4
#define STATUSPORT PORTB
5
#define STATUSLED1 PB3
6
.
7
.
8
.
9
STATUSPORT |= (1 << STATUSLED1);
10
.
11
.
12
.
13
STATUSPORT &= ~(1 << STATUSLED);
14
.
15
.
16
.

Das finde ich eigentlich sehr gut lesebar und ist auf viele verschiedene 
Fälle anwendbar.

von W.S. (Gast)


Lesenswert?

Stefan U. schrieb:
> Danach hatte ich auch gar nicht gefragt.

Erstens hast du gefragt "Was haltet ihr davon?" und zweitens klingt dein 
letzter Beitrag reichlich unverschämt.

Michael K. schrieb:
> STATUSPORT &= ~(1 << STATUSLED);
> Das finde ich eigentlich sehr gut lesebar und ist auf viele verschiedene
> Fälle anwendbar.

Ja, lesbar ist das schon, aber du mußt dich jedesmal daran erinnern, ob 
deine Statusled gegen VCC oder gegen GND geht oder ob davor noch ein 
Transistor ist und so weiter.

Sowas wie "void Led_ein(void)" (notfalls als inline) ist da ein ganzes 
Stück lesbarer, weil es dir gestattet, dich auf deine eigentlichen 
Probleme zu konzentrieren ohne dir Gedanken zu machen, ob du nun Hi oder 
Lo applizieren mußt, um die verdammte Lampe einzuschalten.

W.S.

von M. K. (sylaina)


Lesenswert?

W.S. schrieb:
> Ja, lesbar ist das schon, aber du mußt dich jedesmal daran erinnern, ob
> deine Statusled gegen VCC oder gegen GND geht oder ob davor noch ein
> Transistor ist und so weiter.

Das hatte weiter oben schon mal jemand geschrieben:
1
.
2
.
3
.
4
#define STATUSLED_EIN (PORTB |= (1 << PB1))
5
#define STATUSLED_AUS (PORTB &= ~(1 << PB1))
6
.
7
.
8
.

So kann man es auch machen wenn es beliebt. Aber: Wenn ich ja schon 
vorher weiß wie mein Code zum Ein- und Ausschalten ausschaut (und das 
weiß man immer) kann ich ja die Hardwareverdrahtung entsprechend 
erstellen sodass z.B. ein Pin auf High schalten immer Einschalten 
bedeutet (das ist in meinen Projekten in 100% aller Anwendungen der 
Fall).

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@W.S. (Gast)

>> STATUSPORT &= ~(1 << STATUSLED);
>> Das finde ich eigentlich sehr gut lesebar und ist auf viele verschiedene
>> Fälle anwendbar.

>Ja, lesbar ist das schon, aber du mußt dich jedesmal daran erinnern, ob
>deine Statusled gegen VCC oder gegen GND geht oder ob davor noch ein
>Transistor ist und so weiter.

Eben. Der Sinn von Kapselung und Abstraktion ist, das man sich als 
"Anwender" von Funktionen, und seinen sie noch so trivial, eben NICHT 
darum kümmern muss WIE etwas gemacht wird sondern einfach nur sagt WAS 
gemacht werden soll.

STATUS_LED_ON

Mehr will ich gar nicht wissen und mich um nichts weiter kümmern!

von Falk B. (falk)


Lesenswert?

@Michael Köhler (sylaina)

>So kann man es auch machen wenn es beliebt. Aber: Wenn ich ja schon
>vorher weiß wie mein Code zum Ein- und Ausschalten ausschaut (und das
>weiß man immer) kann ich ja die Hardwareverdrahtung entsprechend
>erstellen sodass z.B. ein Pin auf High schalten immer Einschalten
>bedeutet (das ist in meinen Projekten in 100% aller Anwendungen der
>Fall).

Nö! Genau anders herum wird ein Schuh draus! Die Hardware baut man so, 
wie es für die Hardware am besten ist, ggf. auch mit wilden 
Pinkreuzungen etc. Bestimmte Pegel kann man nicht immer selber 
festlegen, die sind von den äußeren Schaltungen abhängig. Und in 
Software kann man das bliebig schalten und abstrahieren! OK, es gibt 
Ausnahmen, wo die Hardware passend zu Software gemacht werden 
muss/sollte. Z.B. ist ein SPI oder UART an feste Pins gebunden, eine 
Softwareemulation ist möglich aber deutlich leistungsschwächer. 
Ähnliches gilt für Timer- und Interrupteingänge, Output Compare, Input 
Capture etc.

von Falk B. (falk)


Lesenswert?

Ausserdem, die typische Schreibweise

PORTx = (1<<PIN);

ist natürlich auf dem AVR gewachsen, weil die Includefiles für ASM und C 
gemeinsam benutzt wurden. Ein

PORTx = PA0;

wobei PA0 als (1<<0) definiert ist, ist übersichtlicher, einfacher und 
wenige Schreibarbeit. In C braucht man die BITNUMMER so gut wie nie, die 
war nur beim AVR ASM für die Bitbefehle sbi/cbi bzw. sbic/sbis etc. 
nötig.

Zum Glück ist das beim ATXmega mittlerweile anders, dort hat man die 
Bitmasken bzw. Gruppenmasken für die Bits. Hier mal ein Ausschnitt aus 
der


iox128a1.h
1
#define PORT_OPC_gm  0x38  /* Output/Pull Configuration group mask. */
2
#define PORT_OPC_gp  3  /* Output/Pull Configuration group position. */
3
#define PORT_OPC0_bm  (1<<3)  /* Output/Pull Configuration bit 0 mask. */
4
#define PORT_OPC0_bp  3  /* Output/Pull Configuration bit 0 position. */
5
#define PORT_OPC1_bm  (1<<4)  /* Output/Pull Configuration bit 1 mask. */
6
#define PORT_OPC1_bp  4  /* Output/Pull Configuration bit 1 position. */
7
#define PORT_OPC2_bm  (1<<5)  /* Output/Pull Configuration bit 2 mask. */
8
#define PORT_OPC2_bp  5  /* Output/Pull Configuration bit 2 position. */

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Falk B. schrieb:
> PORTx = PA0;
>
> wobei PA0 als (1<<0) definiert ist,

Das ist nicht ganz richtig. Auszug aus iomx8.h:
1
/* PORTB */
2
#define PB7     7
3
#define PB6     6
4
#define PB5     5
5
#define PB4     4
6
#define PB3     3
7
#define PB2     2
8
#define PB1     1
9
#define PB0     0

Es sind also keine Masken. Ja, eigentlich schade.

von Marc S. (marc_s86)


Lesenswert?

Frank M. schrieb:
> Falk B. schrieb:
>> PORTx = PA0;
>>
>> wobei PA0 als (1<<0) definiert ist,
>
> Das ist nicht ganz richtig. Auszug aus iomx8.h:
>
1
> /* PORTB */
2
> #define PB7     7
3
> ...
4
> #define PB0     0
5
>
>
> Es sind also keine Masken. Ja, eigentlich schade.

Falk meinte, dass es so übersichtlicher wäre, aber nicht so ist. beim 
XMega aber schon

von Tom K. (ez81)


Lesenswert?

Falk B. schrieb:
> STATUS_LED_ON
>
> Mehr will ich gar nicht wissen und mich um nichts weiter kümmern!

Ich will nicht mal wissen, ob die LED an einem Portpin hängt oder ob ein 
Bit in einem Array gesetzt wird (das gelegentlich in ein Schieberegister 
rausgetaktet wird) oder ob ein printf("status_led 1\n") dahintersteckt, 
wenn ich die Logik vorher auf dem PC teste.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc S. schrieb:
> Falk meinte, dass es so übersichtlicher wäre, aber nicht so ist.

Ah okay, dann habe ich das missverstanden. Sorry.

von Stefan F. (Gast)


Lesenswert?

@W.S.

>> Danach hatte ich auch gar nicht gefragt. Mir ging es darum, die Zeilen
>> besser lesbar zu machen. Lies nochmal meinen initialen Beitrag.

> klingt dein letzter Beitrag reichlich unverschämt.

Was ist daran unverschämt? Verstehe ich nicht.

von M. K. (sylaina)


Lesenswert?

Falk B. schrieb:
> Die Hardware baut man so,
> wie es für die Hardware am besten ist

Ja genau, und da ich weiß wie mein µC arbeitet bin ich immer bemüht es 
so zu bauen, dass ein High auch einschaltet und ein Low ausschaltet.
Falk B. schrieb:
> Bestimmte Pegel kann man nicht immer selber
> festlegen, die sind von den äußeren Schaltungen abhängig.
Wenn das mal nicht geht kann ich immer noch die #defines tauschen, wohl 
wahr.

Okey, ich bin auch nicht soo der Hardware/Software-Entwickler, ich mach 
das eher nur im Bastelkeller und nur ab und an auch mal im Beruf zur 
Zeit.

von Sheeva P. (sheevaplug)


Lesenswert?

Peter D. schrieb:
> Sheeva P. schrieb:
>> led3.setHigh();
>> led3.setLow();
>
> Hier hat man aber wieder das Problem ist nun setHigh LED an oder aus?

Da hast Du Recht, aber dieses Problem hast Du mit "PORTA |= ~(1 << PA3)" 
doch genauso -- und da siehst Du nichtmal, was an PA3 hängt. Allerdings 
erhöht es die Lesbarkeit in Deinem Sinne und kostet gar nichts, es noch 
ein wenig hübscher zu gestalten:
1
#include <Pin.hpp>
2
#include <Reg.hpp>
3
4
class ActiveLowPin : OutputPin {
5
public:
6
  using OutputPin::OutputPin;
7
  void on(void) { setLow(); }
8
  void off(void) { setHigh(); }
9
};
10
11
int main(void) {
12
  ActiveLowPin led3( PINDEF(A, 1) );
13
14
  while(true) {
15
    led3.on();
16
    led3.off();
17
  }
18
  return 0;
19
}

von Sheeva P. (sheevaplug)


Lesenswert?

Michael K. schrieb:
> Stefan U. schrieb:
>> Danach hatte ich auch gar nicht gefragt. Mir ging es darum, die Zeilen
>> besser lesbar zu machen. Lies nochmal meinen initialen Beitrag.
>
> Warum ist denn für dich z.B.
>
>
1
> PORTB |= (1 << PB1);
2
>
>
> nicht gut lesbar?

Ich kann (und will) nicht für Stefan sprechen, aber daran ist eigentlich 
so ziemlich alles unlesbar. Was sind "PORTB" und "PB1"? Ok, aus dem 
Kontext von AVRs weiß ich, daß es dabei um einen Port und einen Pin 
geht, aber für einen der noch nie mit AVRs zu tun hatte, ist das völlig 
unverständlich. Und die Bitoperationen in C sind einfach potthäßlich, 
weshalb viele -- und auch die Autoren der AVR-Libc anfangs -- sie in 
Funktionen oder Makros wie sbi() und cbi() verpacken. Ohne Schaltplan, 
Datenblatt und Übung mit C-Bitoperationen versteht dabei niemand, was 
dort passiert.

Bei
1
led3.on()
versteht jeder sofort, daß dort offensichtlich die LED mit der Nummer 3 
eingeschaltet wird. Man kann die Instanz dabei sogar noch sprechender 
nach ihrer Funktion benennen, etwa "ledError". Ein
1
ledError.on();
versteht sogar jemand, der noch nie eine Zeile C oder C++ geschrieben 
hat -- und zwar sogar ohne Schaltplan oder Datenblatt.

von M. K. (sylaina)


Lesenswert?

Sheeva P. schrieb:
> Was sind "PORTB" und "PB1"? Ok, aus dem
> Kontext von AVRs weiß ich, daß es dabei um einen Port und einen Pin
> geht, aber für einen der noch nie mit AVRs zu tun hatte, ist das völlig
> unverständlich.

Jemand, der sich noch nie mit AVRs und Co beschäftigt hat wird auch 
nicht wissen was mit ADC und Co gemeint ist. Ich glaube nicht, dass sich 
jemand, der noch nie mit Mikrocontrollern gearbeitet hat, alleine am 
Code sehen wird was was ist. Ganz egal wie leserlich man es gestaltet. 
Ein bisschen Grundwissen gehört schon dazu und zumindest das Datenblatt 
des Mikrocontrollers gehört dann daneben und dann sieht man auch als 
Unwissender sehr schnell was PORTB und PB1 bedeutet. Diese Bezeichnungen 
sind ja nicht aus der Luft gegriffen sondern kommen aus dem Datenblatt 
;)

von Klaus (Gast)


Lesenswert?

Michael K. schrieb:
> Ein bisschen Grundwissen gehört schon dazu und zumindest das Datenblatt
> des Mikrocontrollers gehört dann daneben und dann sieht man auch als
> Unwissender sehr schnell was PORTB und PB1 bedeutet.

Um zu verstehen, was
1
errorled_on()
oder
1
errorled(ON)
bedeutet, muß ich noch nicht mal wissen, ob der Prozessor möglicherweise 
mit Dampf betrieben wird.

MfG Klaus

von M. K. (sylaina)


Lesenswert?

Klaus schrieb:
> bedeutet, muß ich noch nicht mal wissen, ob der Prozessor möglicherweise
> mit Dampf betrieben wird.
Das muss ich hier:
Michael K. schrieb:
> .
> #define STATUSLED_EIN (PORTB |= (1 << PB1))
> #define STATUSLED_AUS (PORTB &= ~(1 << PB1))
> .
auch nicht aber du musst wissen was eine Error-LED ist und was es 
bedeutet wenn da ON oder OFF steht. ;)

von $NAME (Gast)


Lesenswert?

Michael K. schrieb:
> Klaus schrieb:
>> bedeutet, muß ich noch nicht mal wissen, ob der Prozessor möglicherweise
>> mit Dampf betrieben wird.
> Das muss ich hier:
> Michael K. schrieb:
>> .
>> #define STATUSLED_EIN (PORTB |= (1 << PB1))
>> #define STATUSLED_AUS (PORTB &= ~(1 << PB1))
>> .
> auch nicht aber du musst wissen was eine Error-LED ist und was es
> bedeutet wenn da ON oder OFF steht. ;)

Was ist mit:
1
if (PORTB == STATUSLED_EIN)
2
{
3
   ;
4
}

Es könnte ja auch sein dass das makro einen Status oder nur eine Zahl 
ist oder eine Maske.

Wenn das ein Makro ist, meckert da kein Compiler.
Wenn es eine void Funktion ist dagegen schon, mal davon abgesehen, dass 
man es an den Klammern () sehen würde, die bei der Funktion nicht fehlen 
dürfen.
-> Funktion für eine Funktion nehmen und kein Makro

von avr (Gast)


Lesenswert?

Michael K. schrieb:
> Michael K. schrieb:
>> .
>> #define STATUSLED_EIN (PORTB |= (1 << PB1))
>> #define STATUSLED_AUS (PORTB &= ~(1 << PB1))
>> .

Ich hätte gerne mal ein richtiges Argument für Makros... Warum sollte 
man überhaupt Makros verwenden, wenn man sie durch Funktionen ersetzen 
kann, die keinen Nachteil haben? Ich kann die API meines HAL in einer 
Headerdatei definieren und dann je nach Plattform die c-Dateien 
austauschen. Das ist für mich ein elegantes und einheitliches Design. 
Geschwindigkeit und Speicherbedarf ist mit LTO nicht mehr.

In C haben meiner Meinung nach Makros eigentlich nur sehr sehr selten 
etwas verloren. Für Konstanten, weil es kein richtiges const gibt, und 
für Assertion, weil man da _LINE__ und __FILE_ nutzen kann.

Argumente wie Debuggen braucht man nicht und Typsicherheit auch nicht, 
sind keine! Deswegen sind Makros nicht besser.

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


Lesenswert?

avr schrieb:
> Ich hätte gerne mal ein richtiges Argument für Makros... Warum sollte
> man überhaupt Makros verwenden, wenn man sie durch Funktionen ersetzen
> kann, die keinen Nachteil haben?

Weil schon in dieser Annahme ein Fehler steckt. Funktionen haben 
Nachteile. Z.B. daß man sie in C nicht zuverlässig inlinen kann. Und nur 
weil avr-gcc jetzt endlich(!) auch LTO kann, kann das noch lange nicht 
jede andere C-Toolchain auch.  Womöglich weiß auch schon die IDE nichts 
davon und schaltet es nicht ein.

Natürlich gibt es Gründe die gegen bestimmte Arten von Makros sprechen. 
Makros mit Parametern. Makros die zu größeren Mengen Code expandieren. 
Nur trifft eben keiner dieser Gründe auf die Art von Makros zu die wir 
hier diskutieren. Ich finde es engstirnig, Makros zwanghaft zu 
vermeiden. Warum sollte man sich freiwillig eines so mächtigen 
Sprachmittels berauben?

Für mich ist es vielmehr diese irrationale generelle Abneigung gegen die 
Verwendung von Makros, die einer Erklärung bedarf.

von M. K. (sylaina)


Lesenswert?

Es ging darum um den Code (und zwar AVR-Code!) leserlicher zu machen und 
nicht ob Macros oder Funktionen sinnvoller sind.

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

Axel S. schrieb:
> Für mich ist es vielmehr diese irrationale generelle Abneigung gegen die
> Verwendung von Makros, die einer Erklärung bedarf.

Makro ist halt ne andere Programmiersprache als C. Sie ist eigentlich 
nicht wirklich brauchbar, da sie als Sprache nicht turing-vollständig 
ist. Und warum sollte man in zwei Sprachen C und Makro gleichzeitig 
programmieren, wenn man alles zwar in C aber nicht alles in Makro 
erledigen kann.

Und wen interresiert schon "inline" beim Programmieren? Die Vorstellung, 
daß man die Ablaufgeschwindigkeit von Software damit merklich 
beinflussen kann, stammt doch aus der Steinzeit. Die µCs mit denen ich 
zu tun habe, trommeln 16 Bit breit mit 70MHz, das ist mindestens 10 Mal 
so schnell, wie ein original IBM AT. Und der war gut für Wordprozessing, 
Spreadsheets und auch CAD SW. Und selbst ein ESP8266, der zusammen mit 
seinem Flashspeicher weniger als 2€ kostet, hat mindestens 40MHz und 32 
Bit.

Taktgenaues Programmieren ist bei den modernen Strukturen mit 
unterschiedlichen internen Bussen und Caches sowieso nicht möglich. Die 
überschüssige Power, die moderne µCs haben, setze ich für saubere, 
leicht nachvollziehbare Softwarestrukturen ein. Ne Funktion ist halt ne 
Funktion, mit allen ihren Eigenschaften wie lokalen Variablen und der 
Möglichkeit, sie rekursiv einzusetzen. Sie ist getrennt übersetzbar und 
kann auch in einer Objektlibrary stecken. Da passt "inline" nun 
garnicht.

MfG Klaus

von Falk B. (falk)


Lesenswert?

@ Klaus (Gast)

>Und wen interresiert schon "inline" beim Programmieren?

Leute, die schnelle Low Level Aufgaben bearbeiten.

> Die Vorstellung,
>daß man die Ablaufgeschwindigkeit von Software damit merklich
>beinflussen kann, stammt doch aus der Steinzeit.

Nö, die stimmt heute immer noch. Vor allem weil man das GEGENTEIL jeden 
Tag sieht, wo auch im Profibereich nur allzuoft MASSIV CPU Power sinnlos 
verbrannt wird. Nein, ich bin kein ASM-Prediger.

> Die µCs mit denen ich
>zu tun habe, trommeln 16 Bit breit mit 70MHz, das ist mindestens 10 Mal
>so schnell, wie ein original IBM AT. Und der war gut für Wordprozessing,
>Spreadsheets und auch CAD SW. Und selbst ein ESP8266, der zusammen mit
>seinem Flashspeicher weniger als 2€ kostet, hat mindestens 40MHz und 32
>Bit.

Schön, aber darum muss man CPU-Power nicht sinnlos verheizen.

>Taktgenaues Programmieren ist bei den modernen Strukturen mit
>unterschiedlichen internen Bussen und Caches sowieso nicht möglich.

Stimmt. Und in den meisten Fällen auch gar nicht nötig, auch nicht auf 
kleinen Architekturen. ABER!!!

> Die
>überschüssige Power, die moderne µCs haben, setze ich für saubere,
>leicht nachvollziehbare Softwarestrukturen ein.

Dagegen hat doch keiner argumentiert. Es ging hier vor allem um KLEINSTE 
Funktionalitäten und Makros!

> Ne Funktion ist halt ne
>Funktion, mit allen ihren Eigenschaften wie lokalen Variablen und der
>Möglichkeit, sie rekursiv einzusetzen. Sie ist getrennt übersetzbar und
>kann auch in einer Objektlibrary stecken. Da passt "inline" nun
>garnicht.

Das ist Schwarz-Weiß Denken. Nix für mich.

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


Lesenswert?

Klaus schrieb:
> Axel S. schrieb:
>> Für mich ist es vielmehr diese irrationale generelle Abneigung gegen die
>> Verwendung von Makros, die einer Erklärung bedarf.
>
> Makro ist halt ne andere Programmiersprache als C.

Häh? Makros sind keine eigene Programmiersprache, sondern ein fester 
Bestandteil von C. Kennst du dein Werkzeug eigentlich?

> Und warum sollte man in zwei Sprachen C und Makro gleichzeitig
> programmieren, wenn man alles zwar in C aber nicht alles in Makro
> erledigen kann.

Ich lese das jetzt einfach mal als "warum sollte man in C Makros 
verwenden, wenn man es auch ohne machen könnte?". Und dann steht die 
Antwort oben in meinem Post.

> Und wen interresiert schon "inline" beim Programmieren?

Jeden? Also zumindest jeden, der nicht 90% (oder mehr) der verfügbaren 
Performance wegwerfen will. Und zwar ohne guten Grund wegwerfen.
Zähl halt einfach mal die CPU-Zyklen für ein SBI im Vergleich zu einem 
Funktionsaufruf. Womit rechtfertigst du gleich nochmal, daß das jetzt 20 
mal so lange dauert? Und welche Garantie kannst du mir eigentlich dafür 
geben, daß du an anderer Stelle nicht genau so liederlich mit Ressourcen 
umgehst?

> überschüssige Power, die moderne µCs haben, setze ich für saubere,
> leicht nachvollziehbare Softwarestrukturen ein. Ne Funktion ist halt ne
> Funktion, mit allen ihren Eigenschaften wie lokalen Variablen und der
> Möglichkeit, sie rekursiv einzusetzen. Sie ist getrennt übersetzbar und
> kann auch in einer Objektlibrary stecken. Da passt "inline" nun
> garnicht.

Aha. Du hast also nicht nur Makros nicht verstanden, sondern verstehst 
auch "inline" nicht. Jeder blamiert sich halt so gut wie er kann ...

von avr (Gast)


Lesenswert?

Falk B. schrieb:
> @ Klaus (Gast)
>
>>Und wen interresiert schon "inline" beim Programmieren?
>
> Leute, die schnelle Low Level Aufgaben bearbeiten.

Jajaja, mit LTO kein Problem. Außerdem gehören zeitkritische Sachen 
DIREKT in das HAL.

>> Die Vorstellung,
>>daß man die Ablaufgeschwindigkeit von Software damit merklich
>>beinflussen kann, stammt doch aus der Steinzeit.
>
> Nö, die stimmt heute immer noch. Vor allem weil man das GEGENTEIL jeden
> Tag sieht, wo auch im Profibereich nur allzuoft MASSIV CPU Power sinnlos
> verbrannt wird. Nein, ich bin kein ASM-Prediger.

Anscheinend doch. Es wird nämlich KEINE CPU Power verbrannt. NULL.

>> Die µCs mit denen ich
>>zu tun habe, trommeln 16 Bit breit mit 70MHz, das ist mindestens 10 Mal
>>so schnell, wie ein original IBM AT. Und der war gut für Wordprozessing,
>>Spreadsheets und auch CAD SW. Und selbst ein ESP8266, der zusammen mit
>>seinem Flashspeicher weniger als 2€ kostet, hat mindestens 40MHz und 32
>>Bit.
>
> Schön, aber darum muss man CPU-Power nicht sinnlos verheizen.

Tut man auch nicht.

>>Taktgenaues Programmieren ist bei den modernen Strukturen mit
>>unterschiedlichen internen Bussen und Caches sowieso nicht möglich.
>
> Stimmt. Und in den meisten Fällen auch gar nicht nötig, auch nicht auf
> kleinen Architekturen. ABER!!!
>
>> Die
>>überschüssige Power, die moderne µCs haben, setze ich für saubere,
>>leicht nachvollziehbare Softwarestrukturen ein.
>
> Dagegen hat doch keiner argumentiert. Es ging hier vor allem um KLEINSTE
> Funktionalitäten und Makros!

Ja und? Die Funktionen haben keinen Nachteil. Absolut keinen.

>> Ne Funktion ist halt ne
>>Funktion, mit allen ihren Eigenschaften wie lokalen Variablen und der
>>Möglichkeit, sie rekursiv einzusetzen. Sie ist getrennt übersetzbar und
>>kann auch in einer Objektlibrary stecken. Da passt "inline" nun
>>garnicht.
>
> Das ist Schwarz-Weiß Denken. Nix für mich.

Aha. Und dein Makroonly Denken ist nicht schwarz-weiß?

Axel S. schrieb:
> Jeden? Also zumindest jeden, der nicht 90% (oder mehr) der verfügbaren
> Performance wegwerfen will. Und zwar ohne guten Grund wegwerfen.

90%? In jedem meiner Programme machten Portzugriffe nicht einmal 1% aus.

Axel S. schrieb:
> Weil schon in dieser Annahme ein Fehler steckt. Funktionen haben
> Nachteile. Z.B. daß man sie in C nicht zuverlässig inlinen kann.

Das kann man beim gcc schon. Und bei anderen besseren Compilern 
sicherlich auch. Man muss nur sein Tool kennen.

> Und nur
> weil avr-gcc jetzt endlich(!)
Das geht schon länger.
> auch LTO kann, kann das noch lange nicht
> jede andere C-Toolchain auch.  Womöglich weiß auch schon die IDE nichts
> davon und schaltet es nicht ein.

Dann kennst du dein Tool wohl nicht. Das ist doch kein Argument.

> Für mich ist es vielmehr diese irrationale generelle Abneigung gegen die
> Verwendung von Makros, die einer Erklärung bedarf.

Ich verwende durchaus Makros. Z.B. für Assertion. Das mache ich sogar in 
C++. Aber an Stellen wo man keine Makros braucht, muss man sie nicht 
nutzen. Es geht mir um eine eine einheitliche Softwarearchitektur, die 
zu meinem HAL passt. Das vermeidet Fehler und macht die Architektur 
übersichtlicher. Übersichtlichkeit vermeidet auch Fehler. Makros sind 
aber eher Fehleranfällig. Es ist halt einfach eine Textersetzung. Und 
spätestens wenn du mal im Safety-Bereich arbeitest, kann du dir deine 
ganzen Makros sowieso sparen.

von M. K. (sylaina)


Lesenswert?

Also ich weiß ja nicht wie das bei euch ist aber bei mir stell ich den 
avr-gcc mit dem Makefile ein und die IDE schubst nur das Makefile an.

However, meint ihr nicht dass ihr mit euerer Diskussion schon ziemlich 
weit weg seit vom Threadthema?

von Klaus (Gast)


Lesenswert?

Axel S. schrieb:
>> Und wen interresiert schon "inline" beim Programmieren?
>
> Jeden? Also zumindest jeden, der nicht 90% (oder mehr) der verfügbaren
> Performance wegwerfen will. Und zwar ohne guten Grund wegwerfen.
> Zähl halt einfach mal die CPU-Zyklen für ein SBI im Vergleich zu einem
> Funktionsaufruf.

Um bei deinen 90% zu bleiben: mehr als 90% des Codes eines modernen µC 
gesteuerten Gerätes ist das Userinterface, wenn nicht mehr. Wieviel 
Zyklen die CPU einer Waschmaschine braucht, die Laugenpumpe 
einzuschalten, ist doch absolut unerheblich. Da wird mehr Zeit 
verbraucht, das ganze Umfeld diese Vorgangs ins Log zu speichern.

> Womit rechtfertigst du gleich nochmal, daß das jetzt 20 mal so lange
> dauert?

Es ist egal, es interessiert niemand, niemand merkt es. Es macht das 
Produkt nicht besser, billiger sowieso nicht. Time to Market wird nicht 
besser und als Alleinstellungsmerkmal kann man das dem Kunden noch nicht 
mal erklären. Es streichelt höchsten das Ego des Programmierers.

Eigentlich sollte man es noch langsamer machen, in dem man nicht in C 
programmiert, sondern eine wesentlich höhere, möglicherweise sogar 
interpretierte Sprache einsetzt. Wo Geschwindigkeit bei der Software 
wirklich wichtig ist, ist bei der Erstellung von möglichst fehlerfreiem, 
portablen und wartbaren Code. Das bringt einem Time to Market, 
Produktvielfalt und Weiterentwicklung mit geringstem Aufwand. Und da muß 
man soviel Unterstützung von Tools in Anspruch nehmen, wie möglich. Und 
jeder Trick, der diese Tools ausbremst, ist schädlich.

Un zu guter letzt: wenns mal richtig schnell gehen soll, wirklich 
Real-Time, sind CPUs zu langsam. Cycle by Cycle Stromüberwachung in 
einem Switcher, Umrichter o.ä. im Megaherz Takt braucht einen anderen 
Ansatz, z.B. ein FPGA. Wärend die Bitfummler noch nach einem 
verbesserten "SBI" suchen, verdoppelt sich gerade die Geschwindigkeit 
der Leistungsschalter. Schon wieder zu langsam.

MfG Klaus

von Falk B. (falk)


Lesenswert?

@ Klaus (Gast)

>Um bei deinen 90% zu bleiben: mehr als 90% des Codes eines modernen µC
>gesteuerten Gerätes ist das Userinterface, wenn nicht mehr. Wieviel
>Zyklen die CPU einer Waschmaschine braucht, die Laugenpumpe
>einzuschalten, ist doch absolut unerheblich. Da wird mehr Zeit
>verbraucht, das ganze Umfeld diese Vorgangs ins Log zu speichern.

Du lenkst ab! Das man auf den höheren Ebenen nicht zum CPU-Takt 
Erbsenzähler werden muss ist unbestritten. Für eine Status-LED und 
ähnlichen Kram auch, da kann man auch Arduino-Style digital_write() 
nehmen!
Aber wenn es ans Eingemacht geht und es mal FLOTT gehen soll/muss, 
sollte man schon effizient arbeiten.

>Eigentlich sollte man es noch langsamer machen, in dem man nicht in C
>programmiert, sondern eine wesentlich höhere, möglicherweise sogar
>interpretierte Sprache einsetzt.

Ich vermisse einen Smily.

>Wo Geschwindigkeit bei der Software
>wirklich wichtig ist, ist bei der Erstellung von möglichst fehlerfreiem,
>portablen und wartbaren Code. Das bringt einem Time to Market,
>Produktvielfalt und Weiterentwicklung mit geringstem Aufwand.

Schon wieder Schwarz-Weiß Denken. Das ist auch der Grund, warum ein 
Maustreiber heute 10MB++ groß ist . . .

>Un zu guter letzt: wenns mal richtig schnell gehen soll, wirklich
>Real-Time, sind CPUs zu langsam. Cycle by Cycle Stromüberwachung in
>einem Switcher, Umrichter o.ä. im Megaherz Takt braucht einen anderen
>Ansatz, z.B. ein FPGA. Wärend die Bitfummler noch nach einem
>verbesserten "SBI" suchen, verdoppelt sich gerade die Geschwindigkeit
>der Leistungsschalter. Schon wieder zu langsam.

Jaja.

von avr (Gast)


Lesenswert?

@Falk

Leider hat er recht. Auch wenn du das nicht glauben willst.

von Klaus (Gast)


Lesenswert?

Falk B. schrieb:
> Ich vermisse einen Smily.

Sollte auch keiner hin

Falk B. schrieb:
>>Wo Geschwindigkeit bei der Software
>>wirklich wichtig ist, ist bei der Erstellung von möglichst fehlerfreiem,
>>portablen und wartbaren Code. Das bringt einem Time to Market,
>>Produktvielfalt und Weiterentwicklung mit geringstem Aufwand.
>
> Schon wieder Schwarz-Weiß Denken.

Dann den letzten Satz noch mal etwas länger:

Das bringt einem Time to Market, Produktvielfalt und Weiterentwicklung 
mit geringstem Aufwand und verdient so das Gehalt des Programmierers.

MfG Klaus

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


Lesenswert?

avr schrieb:
>
> Leider hat er recht. Auch wenn du das nicht glauben willst.

Na da haben sich ja die zwei Richtigen gefunden. Ihr seit genau die 
Leute, denen wir Mobiltelefone "verdanken" die Vierkern-CPU mit 
Gigahertz Takt brauchen und deren Akkus nur mit Mühe und Not einen Tag 
halten. Aber es war ja ohnehin alles gesagt. Überlassen wir diesen 
Thread dem Thread-Kaperer und dem Troll.

Ich bin dann mal weg

von avr (Gast)


Lesenswert?

Axel S. schrieb:
> Na da haben sich ja die zwei Richtigen gefunden. Ihr seit genau die
> Leute, denen wir Mobiltelefone "verdanken" die Vierkern-CPU mit
> Gigahertz Takt brauchen und deren Akkus nur mit Mühe und Not einen Tag
> halten.

Dann mach es halt besser. Deine Software hätte bestimmt so viele Bugs 
dass kein Mensch sie benutzen wollte. Ich schätze du hast einfach keine 
Ahnung von komplexere Software. Der Linux Kernel alleine hat 20 
Millionen LOC. Bugs zu vermeiden fängt schon bei einfachen Sachen an. 
Z.B. ein einheitliches Design, das jeder auf den ersten Blick versteht. 
Einheitlich bedeutet auch nicht Makros und Funktionen für die Hardware, 
sondern nur Funktionen. Das beschleunigt auch das Codereview. Jede 
Vereinfachung macht den Code verständlicher. Und damit sinken auch im 
Schnitt die Bugs/LOC.

von G4st (Gast)


Lesenswert?

Die Pro Funktion, Pro SW-Design, Pro SW-Architecture, Pro einheitliche 
Umsetzung Fraktion hat Recht.

Man hat relativ schnell festgestellt, das eine Software die performant 
und ressourcensparend ist zwar entwickelt werden kann, aber in keinem 
Verhaeltnis zum Aufwand und der Entwicklungszeit steht. Auch das 
optimieren von komplexen System hat sich als grosser Aufwandtreiber 
herausgestellt.

Heute ist dem Kunden eine 90% Loesung lieber als eine 100% Loesung die 
dafuer doppelt so lange zum Entwickeln braucht und dreimal soviel 
kostet.

Um jetzt dennoch ein hohes SW Niveau halten zu koennen werden die 
Parameter fuer schnelles Entwickeln und Kostenreduktion optimiert. 
Resultierend wird sehr viel Platformentwicklung betrieben, sowie dem zu 
Grunde liegenden Code-Reuse. Weitere Methoden wie Continous Integration 
und Automated Testing unterstuetzen genau diesen "neuen" Ansatz.

Was dazu kommt ist, dass Entwickler in einem Projekt oft wechseln. D.h. 
Einarbeit ist ein ganz wichtiger Punkt heutzutage. Eine Software in der 
ein neuer Mitarbeiter nach 3 Wochen schon produktiv arbeiten kann weil 
das Konzept und die Ausfuehrung sehr einfach gestaltet ist hat eindeutig 
Vorteile gegenueber einer Software die mehr Aufwand fuer die Einarbeit 
braucht.

In den meisten SW lastigen Unternehmen sind diese Paradigmen schon 
angekommen und werden gelebt. Aber wir stossen durchaus auch noch auf 
kleinere Unternehmen (meist so ~10 Personen Unternehmen mit ueberwiegend 
E-Technikern als SW Entwickler) die gerne performante, 
ressourcensparende  Software als Ziel haben. Diese Klagen IMMER, dass 
der Kunde nicht verstehe das ordentliche SW Geld kostet und das die 
Konkurenzsoftware "Murks" sei.
Diese Unternehemen werden aber immer weniger. Der Preisdruck und vor 
allem mit der Geschwindigkeit mit der neue Features von der Konkurenz 
entwickelt werden kann sind hier ausschlaggebend.

Alles in allem wird eine Software die Funktionen statt Macros benutzt 
nicht die Welt veraendern. Aber der Gedanke dabei ist der Richtige.

Das ist der Hintergrund warum Themen wie 
/Einheitlichkeit/Abstraktion/Kapselung/Portabilitaet hoeher gewichtet 
werden als der schnellste, kleine Code. Ist im Moment der aktuelle Stand 
der Technik und wird auch genau so hochschulseitig auch gelehrt.

mfg
 euer G4st

von S. R. (svenska)


Lesenswert?

Es ist mal wieder schön zu sehen, wie ihr groben Unfug (nach)labert.

Niemand hat behauptet, dass man auf eine ordentliche Softwarearchitektur 
im Namen der Performance verzichten muss. Niemand hat behauptet, dass 
Geschwindigkeit über alles geht. Trotzdem argumentiert ihr gegen diesen 
Strohmann. Seid ihr so blöde, oder wollt ihr nur trollen?

Aber schießt mal weiter in den Nebel, so bindet ihr eure Zeit und stört 
nicht woanders.

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.