C: Kann man mittels #define einen Wert zurück geben?

OP #6860988
Lesenswert?

Gibt es eigentlich eine Möglichkeit von einer Makrodefinition einen Wert 
zurück zu geben? Hier mal ein Beispiel, was ich meine.
1
myfoo.c
2

3
unsigned * myFoo (unsigned *p_array, unsigned size)
4
{
5
  // ... tue was
6
  return p_array;
7
}
8

9
myfoo.h
10

11
#define CreateMyArray (name, size)       \
12
  static unsigned name [size];           \
13
  myFoo (name, size)
14

15
main.c
16

17
#include "myfoo.h"
18
unsigned *p_myarray = NULL;
19

20
main() {
21
  p_myarray = CreateMyArray(myArray, 256);
22
}

D.h. den Zeiger den myFoo zurück gibt, möchte ich gern an p_myarray 
zuweisen.

Ich habe so etwas schon mal gesehen, wo es funktioniert. Das ist aber 
nur ein sehr einfaches Makro.
1
#define OS_ATOMIC_READ(expr)  (__builtin_disable_interrupts(), _OS_Temp = (expr), __builtin_enable_interrupts(), _OS_Temp)

Gibt es da einen Trick?

Ich weiß, da gibt es andere Möglichkeiten, aber malloc() möchte ich für 
ein einfaches Programm gerne vermeiden.

Gruß, Steffen
Gast #6861006
Lesenswert?

Ste N. schrieb:
> Gibt es eigentlich eine Möglichkeit von einer Makrodefinition einen Wert
> zurück zu geben?

Nein, denn ein #define ist nur eine Textersetzung vor der Übersetzung.
1
#define CreateMyArray (name, size)       \
2
  static unsigned name [size];           \
3
  myFoo (name, size)
4

5
  p_myarray = CreateMyArray(myArray, 256);

Das würde hier also folgendes ergeben:
1
p_myarray = static unsigned myArray[256];
2
myFoo(myArray, 256)

Wenn DU etwas zurück haben willst, brauchst Du schon eine Funktion.
Gast #6861035
Lesenswert?

wer sagt, das ein macro nicht auch eine funktion definieren darf?

Der funktionsnaume darf dann halt nicht der macro name sein, ... das ist 
halt zu beachten. Und du must an einer stelle im code dein macro einmal 
"Aufrufen" damit die notwendige funktion auch im code auftaucht.

und wenn das ganze dann noch parameterisierte macros sind fängt der 
spass erst richtig an, ... Wobei genau dann macht man das eigentlich 
damit man sich copy and past spart.
Gast #6861126
Lesenswert?

Was für ein Geschwurbel. Da blickt dann doch gar keiner mehr durch.
Spätestens nach 3 Monaten fliegt einem das um die Ohren.

Anfänger sollten keine #define verwenden dürfen.

Vergiss #define. Mach ein richtige Funktion. Und lass den Compiler das 
optimieren.
Gast #6861139
Lesenswert?

Rolf M. schrieb:
> Weil das erzeugte statische Array nur so lange existiert, bis die
> Funktion zurückkehrt, aber offenbar auch danach noch benötigt wird.

Also, wenn so ein Array nicht auf dem Heap erzeugt wird und auch nicht 
als lokale Variable auf dem Stack, dann bleibt nur noch der gewöhnliche 
RAM übrig, also eine globale Variable, die ihren Platz auf alle 
Ewigkeiten belegt. Wenn also dynamisch, dann ist eine Heapverwaltung 
fällig.

OK, man könnte das Array vorher und/oder hinterher auch für etwas 
anderes benutzen, aber man setzt sich damit selber in die Nesseln.

W.S.
Gast #6861150
Lesenswert?

PittyJ schrieb:
> Anfänger sollten keine #define verwenden dürfen.

Wieder mal so eine kategorische Aussage, die eigentlich unhaltbar ist. 
Wer beurteilt denn, wer irgendwann einmal den Titel eines Nichtanfängers 
verliehen bekommt und ab da besagtes #define verwenden darf?

Abgesehen davon ist die Programmiersprache C quasi kastriert, wenn man 
sowas wie #define nicht verwenden darf. In C hat man keine solchen Dinge 
wie z.B. den 'const' Abschnitt in Pascal, wo man Konstanten definieren 
kann. Der Preprozessor ist ein wesentlicher Bestandteil des Ganzen in C.

Aber eines stimmt: Man kann sich mit dem Definieren von Macros auch 
zurückhalten. Auch als Anfänger.

W.S.
#6861170
Lesenswert?

Rolf M. schrieb:
> Weil das erzeugte statische Array nur so lange existiert, bis die
> Funktion zurückkehrt, aber offenbar auch danach noch benötigt wird.

Nein!

Der Witz an statischen Variablen ist doch, daß sie ab Programmstart 
durchgehend existieren.

Weil das Feld in diesem Fall lokal definiert ist (wenn auch statisch), 
ist es über den Variablennamen nur innerhalb der Funktion erreichbar.
Aber über Zeiger oder sonstwie auch außerhalb der Funktion.

Nur automatische Variablen liegen auf dem Stack und werden beim 
Verlassen eines Blocks bzw. der Funktion aufgelöst.
#6861222
Lesenswert?

W.S. schrieb:
> In C hat man keine solchen Dinge
> wie z.B. den 'const' Abschnitt in Pascal, wo man Konstanten definieren
> kann.

Aha. Bring' dich mal auf Stand. Seit 21 Jahren kann man Konstanten 
definieren.

Rolf M. schrieb:
> Weil das erzeugte statische Array nur so lange existiert, bis die
> Funktion zurückkehrt, aber offenbar auch danach noch benötigt wird.

Wenn man denn unbedingt will, kann man auch das. Arrays können zwar kein 
Funktionsergebnis sein, structs können das aber durchaus. Und arrays 
können auch Bestandteil von structs sein.

Ob das allerdings empfehlenswert ist, steht auf einem anderen Blatt.
OP #6861227
Lesenswert?

Erst mal Danke für den Input. Das mit dem Array ist ja nur ein Beispiel. 
Was ich eigentlich will, das ein Struct mit einem variablen Datenfeld 
erstellt werden kann, aber eben ohne malloc() und ein Teil der Daten, 
wie z.B. der Name, im ROM liegt. Der Name wird im Makro automatisch aus 
den Parametern generiert. Und genau das geht eben mit einer Funktion 
nicht, oder doch?

Alle Structs und dessen Größe stehen schon bei Programmerstellung fest, 
sollen aber trotzdem variabel bleiben. Das hat für mich den Vorteil, das 
eben schon der Compiler meckert wenn der Speicher verbraucht ist. Das 
funktioniert ja soweit auch hervorragend, bis auf das Zurückgeben des 
Zeigers. Bis jetzt mache ich das über einen Funktionsparameter, aber das 
ist eben nicht ganz so elegant. Wenn ich den Zeiger nicht unbedingt 
benötige, kann ich ihn nicht einfach weglassen.

Wie man an dem obigen Beispiel mit dem ATOMIC_READ sieht, scheint es ja 
auch irgendwie mit Makros zu gehen.
Moderator #6861297
Lesenswert?

Ste N. schrieb:
> Gibt es eigentlich eine Möglichkeit von einer Makrodefinition einen Wert
> zurück zu geben? Hier mal ein Beispiel, was ich meine.

Beim GCC sind solche Dinge mit Statement Expressions möglich. Das ist
aber eine GCC-spezifische Spracherweiterung:

  https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

Ich persönlich bin kein Freund solcher Spracherweiterungen. Ordentlicher
C-Code sollte IMHO mit
1
gcc -std=c18 -pedantic-errors

fehlerfrei kompiliert werden.

> Ich habe so etwas schon mal gesehen, wo es funktioniert. Das ist aber
> nur ein sehr einfaches Makro.
>
> #define OS_ATOMIC_READ(expr)  (__builtin_disable_interrupts(), _OS_Temp
> = (expr), __builtin_enable_interrupts(), _OS_Temp)

In diesem Fall besteht der Makrorumpf nur aus einem einzelnen Ausdruck,
der natürlich – wie jeder Ausdruck, der nicht vom Typ void ist – ein
Ergebnis hat, das von einem aufrufenden Programmteil bspw. einer
Variable zugewiesen werden kann.

In deinem Beispiel enthält der Makrorumpf aber zusätzlich noch eine
Deklaration, weswegen dein Vorhaben nur mit der o.g. Spracherweiterung
realisierbar ist.

Markus F. schrieb:
> W.S. schrieb:
>> In C hat man keine solchen Dinge
>> wie z.B. den 'const' Abschnitt in Pascal, wo man Konstanten definieren
>> kann.
>
> Aha. Bring' dich mal auf Stand. Seit 21 Jahren kann man Konstanten
> definieren.

Benamste Kompilezeitkonstanten sind in C – anders als in C++ –
nur mit #define möglich. Mit dem Schlüsselwort const werden
Read-Only-Variablen deklariert, was aber nicht dasselbe ist.
#6861320
Lesenswert?

Klaus W. schrieb:
> Rolf M. schrieb:
>> Weil das erzeugte statische Array nur so lange existiert, bis die
>> Funktion zurückkehrt, aber offenbar auch danach noch benötigt wird.
>
> Nein!
>
> Der Witz an statischen Variablen ist doch, daß sie ab Programmstart
> durchgehend existieren.

Da hast du natürlich recht. Das gilt selbstverständlich nur für 
nicht-statische lokale Variablen. Mea culpa.

Ste N. schrieb:
> Alle Structs und dessen Größe stehen schon bei Programmerstellung fest,
> sollen aber trotzdem variabel bleiben.

Das verstehe ich nicht ganz. Nicht nur die Größe, sondern alle Elemente 
mit deren jeweiligen Typ und Position innerhalb der Struct sind zur 
Compilezeit bekannt. Man spricht sie über den bei der Definition des 
Typs bereits vergebenen Namen an. Was willst du da variabel machen?

> Das hat für mich den Vorteil, das eben schon der Compiler meckert wenn
> der Speicher verbraucht ist. Das funktioniert ja soweit auch
> hervorragend, bis auf das Zurückgeben des Zeigers. Bis jetzt mache ich
> das über einen Funktionsparameter, aber das ist eben nicht ganz so
> elegant. Wenn ich den Zeiger nicht unbedingt benötige, kann ich ihn nicht > 
einfach weglassen.

Aber ohne den Zeiger kannst du doch gar nicht drauf zugreifen.
Gast #6861353
Lesenswert?

Ste N. schrieb:
> Was ich eigentlich will, das ein Struct mit einem variablen Datenfeld
> erstellt werden kann,
Das nennt man "dynamische Speicherverwaltung" oder Heap, was du da 
nutzen möchtest.

Ste N. schrieb:
> aber eben ohne malloc()
Ach...
Wie möchte es der Herr denn: Statisch oder dynamisch?

Ste N. schrieb:
> Und genau das geht eben mit einer Funktion
> nicht, oder doch?
Funktionen legen ihre lokalen Variablen auf dem Stack an.
Aber dann darfst du die Adresse nicht per Return weiterreichen.

Ste N. schrieb:
> Alle Structs und dessen Größe stehen schon bei Programmerstellung fest,
> sollen aber trotzdem variabel bleiben.
Also eine konstante Größe, welche variabel ist?
Ich sehe da einen Widerspruch!
Du nicht?
OP #6861380
Lesenswert?

Yalu X. schrieb:
> Beim GCC sind solche Dinge mit Statement Expressions möglich. Das ist
> aber eine GCC-spezifische Spracherweiterung:
>
>   https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

Ist schon Krass! 4 Klammern an der richtigen Position haben das 
"Problem" gelöst.
1
#define CreateMyArray (name, size)       \
2
  ({static unsigned name [size];         \
3
    myFoo (name, size);})

So funktioniert es und wird Fehlerfrei und ohne Warnungen übersetzt!

Selbst mit der Option strict-ansi wird es erfolgreich übersetzt, 
allerdings mit reichlich Warnungen, darunter auch Kommentare mit //. 
Aber damit kann ich gut leben, strict-ansi nutze ich nicht und es ist ja 
nur für mich.

Also Danke für den Input Yalu, wieder was gelernt!
OP #6861399
Lesenswert?

EAF schrieb:
> Ste N. schrieb:
>> Was ich eigentlich will, das ein Struct mit einem variablen Datenfeld
>> erstellt werden kann,
> Das nennt man "dynamische Speicherverwaltung" oder Heap, was du da
> nutzen möchtest.

ich glaube du hast mein Anliegen nicht verstanden...

> Ste N. schrieb:
>> aber eben ohne malloc()
> Ach...
> Wie möchte es der Herr denn: Statisch oder dynamisch?

statisch

> Ste N. schrieb:
>> Und genau das geht eben mit einer Funktion
>> nicht, oder doch?
> Funktionen legen ihre lokalen Variablen auf dem Stack an.
> Aber dann darfst du die Adresse nicht per Return weiterreichen.

deswegen ja static

> Ste N. schrieb:
>> Alle Structs und dessen Größe stehen schon bei Programmerstellung fest,
>> sollen aber trotzdem variabel bleiben.
> Also eine konstante Größe, welche variabel ist?
> Ich sehe da einen Widerspruch!
> Du nicht?

Nö! Variabel sollen sie ja zur Compilezeit sein, nicht zur Laufzeit.

Am Ende sieht mein Makro so aus.
1
#define MERGE_(a,b)   a##b
2
#define STRINGIFY_(a) #a
3

4
#define CreateMyStruct(mystruct,size)                            \
5
  ({const char MERGE_(mystruct, _name)[] = STRINGIFY_(mystruct); \
6
    static myStruct_t MERGE_(mystruct, _struct);                 \
7
    static unsigned MERGE_(mystruct, _array)[size];              \
8
    _CreateStruct ( &MERGE_(mystruct, _struct),                  \
9
                    MERGE_(mystruct, _name),                     \
10
                    MERGE_(mystruct, _array),                    \
11
                    size);})

Also ich finde es genial einfach!
OP #6861405
Lesenswert?

Dazu muß ich noch sagen, das in _CreateStruct() noch viel mehr passiert. 
Unter anderem wird aus den Structs eine verkette Liste erstellt, welche 
eben Arrays unterschiedlicher Länge beinhalten kann.
Wenn ich jetzt jeden Eintrag von Hand erstellen sollte, fände ich das 
ziemlich umständlich.
Gast #6861440
Lesenswert?

1
#define CreateMyStruct(name,size)    \
2
  ({static myStruct_t s;             \
3
    static unsigned   a[size];       \
4
    _CreateStruct(&s, #name, a, size})

Das sollte identisch sein.

O.T.: mit einem dritten Parameter und Zuweisung in der letzten Zeile 
wäre es auch ohne Erweiterung nutzbar.
#6861475
Lesenswert?

Ste N. schrieb:
>> Ste N. schrieb:
>>> Alle Structs und dessen Größe stehen schon bei Programmerstellung fest,
>>> sollen aber trotzdem variabel bleiben.
>> Also eine konstante Größe, welche variabel ist?
>> Ich sehe da einen Widerspruch!
>> Du nicht?
>
> Nö! Variabel sollen sie ja zur Compilezeit sein, nicht zur Laufzeit.

Das sind sie doch einfach durch Änderung des struct-Typs. Ich sehe aber 
nicht, wie dir das Makro dabei hilft.
OP #6861542
Lesenswert?

A. S. schrieb:
>
1
> #define CreateMyStruct(name,size)    \
2
>   ({static myStruct_t s;             \
3
>     static unsigned   a[size];       \
4
>     _CreateStruct(&s, #name, a, size})
5
> 
6
>
>
> Das sollte identisch sein.
>
> O.T.: mit einem dritten Parameter und Zuweisung in der letzten Zeile
> wäre es auch ohne Erweiterung nutzbar.

Kannst Du das bitte noch mal näher erläutern?

Das mit dem String ist wirklich ne sehr gute Idee, manchmal sieht man 
den Wald vor lauten Bäumen nicht... aber der Rest geht so leider nicht. 
Das Makro kann ja dann nur 1x aufrufen werden und dafür bräuchte ich die 
ganzen Klimmzüge tatsächlich nicht. Beim nächsten Aufruf gibt es s und a 
schon und der Compiler meckert, und zwar zu recht.

So kann ich in meiner main() einfach nur

p_myA = CreateMyStruct (a, 256);
p_myB = CreateMyStruct (b, 128);
p_myC = CreateMyStruct (c, 64);
p_myD = CreateMyStruct (d, 256);

aufrufen und alles weitere wird automatisch abgeleitet.

A. S. schrieb:
> Kannst du die vielen erzeugten Namen nutzen? Im Editor oder Debugger?
> Fall nicht, lass sie weg. Nach außen ist ja nur der string-inhalt
> sichtbar.

Den Namen benötige ich wirklich nur zum debuggen. Könnte man mit einem 
weiteren #define bei Bedarf auch ausblenden ;) Aber dann wirds am Ende 
wirklich unübersichtlich...

Nop schrieb:
> Für persönlichen Gebrauch sicherlich cool. In einem professionellen
> Code-Review? Keine Chance für den ganzen Ansatz.

Da gebe ich dir natürlich vollkommen recht! Wie gesagt es ist eine 
private Spielerei. Das Makro wird wirklich nur im Initialisierungsteil 
der main() aufgerufen. Das ich das nicht in eine Schleife oder if/then 
Abfrage setzen kann, ist klar.

Rolf M. schrieb:
>> Nö! Variabel sollen sie ja zur Compilezeit sein, nicht zur Laufzeit.
>
> Das sind sie doch einfach durch Änderung des struct-Typs. Ich sehe aber
> nicht, wie dir das Makro dabei hilft.

Das hilft mir insofern, das es die Deklaration extrem unkompliziert 
macht. Zumindest für mich, siehe oben.
OP #6861574
Lesenswert?

A. S. schrieb:
> Ste N. schrieb:
>> Beim nächsten Aufruf gibt es s und a schon und der Compiler meckert, und
>> zwar zu recht.
>
> Aber doch nur statc in einem Block in { }.
>
> Da kannst Du beliebig viele Blöcke von haben.

Funktioniert tatsächlich! Das wird ja immer besser und macht die Sache 
extrem übersichtlich. Das die Klammern einen Block abschotten, hätte ich 
jetzt nicht etwartet und deswegen auch nie probiert.

Danke!
#6861691
Lesenswert?

Ich ahne langsam, was du vorhast.
Ich glaube dir auch, daß es in C mit dem Praeprozessor machbar ist, und 
sicher eine nette Spielerei.

Aber nüchtern betrachtet, geht sowas in C++ mit templates sicher 
wesentlich eleganter und möglicherweise besser.
Nachdem der gcc ja auch C++ kann, wäre es zumindest eine Überlegung 
wert?
#6861711
Lesenswert?

Das wäre mal wieder eine Anwendung für den sogenannten X-macro-trick der 
nicht so bekannt ist.
1
// Liste
2
#define MY_STRUCTURES \
3
 MY_STRUCT(s1, 42 )  \
4
 MY_STRUCT(s2, 174 )  \
5
 MY_STRUCT(s3, 22 )  \
6

7
// Expansion 
8
#define MY_STRUCT(name, size)  \
9
typedef struct {  \
10
int var[size]; \
11
} name; 
12
MY_STRUCTURES 
13
#undef MY_STRUCT 
14

15
Daraus macht der Preprozessor dann ::
16

17

18
typedef struct { int var[42]; } s1;
19
typedef struct { int var[174]; } s2;
20
typedef struct { int var[22]; } s3;
Angehängte Dateien:
Gast #6861720
Lesenswert?

he he he, ...
Hat sich einer mal mit Zephyr angeschaut?

Da werden OS Strukturen  PIN Configuration  ... genau mit solchen 
macros angelegt und teilweise wird dan im macro wider auf andere macros 
zugegriffen,

Auch im Linuz kernel sind mir solche macros schon begegnet, war glaube 
ich der part power rails / Frequanzy scalling
#6861745
Lesenswert?

BLE schrieb:
> he he he, ...
> Hat sich einer mal mit Zephyr angeschaut?
>
> Da werden OS Strukturen  PIN Configuration  ... genau mit solchen
> macros angelegt und teilweise wird dan im macro wider auf andere macros
> zugegriffen,
>
> Auch im Linuz kernel sind mir solche macros schon begegnet, war glaube
> ich der part power rails / Frequanzy scalling

Das war schon zu Zeit der pdp11 bekannt ;-)

@ Ste N.
Du kannst auch damit den Datentyp deiner variable ändern ...
1
// Liste
2
#define MY_STRUCTURES \
3
 MY_STRUCT(s1, 42 , int)  \
4
 MY_STRUCT(s2, 174, char )  \
5
 MY_STRUCT(s3, 22, float )  \
6

7
// Expansion 
8
#define MY_STRUCT(name, size, vtype)  \
9
typedef struct {  \
10
vtype var[size]; \
11
} name; 
12
MY_STRUCTURES 
13
#undef MY_STRUCT

ergibt:

typedef struct { int var[42]; } s1;
typedef struct { char var[174]; } s2;
typedef struct { float var[22]; } s3;
#6861756
Lesenswert?

Klaus W. schrieb:
> Ich ahne langsam, was du vorhast.
> Ich glaube dir auch, daß es in C mit dem Praeprozessor machbar ist, und
> sicher eine nette Spielerei.
>
> Aber nüchtern betrachtet, geht sowas in C++ mit templates sicher
> wesentlich eleganter und möglicherweise besser.
> Nachdem der gcc ja auch C++ kann, wäre es zumindest eine Überlegung
> wert?

In C++ gibt es dafür std::array
Gast #6861775
Lesenswert?

Wozu das Ganze?
Ich bin da eher für klare Verhältnisse, wozu auch der Verzicht auf 
umfangreichere Macros gehört. System KISS sozusagen. Sowas ist bei 
gründlicher Denk-Vorarbeit sowohl einfacher zu schreiben als auch 
leichter zu warten. Man muß nicht jede Pirouette drehen, die in der 
Sprachdefinition nicht ausdrücklich verboten ist.

W.S.
Gast #6862023
Lesenswert?

Ste N. schrieb:
> Das wird ja immer besser und macht die Sache
> extrem übersichtlich.

Deine Aufgabe ist üblich: Eine bekannte Struktur mit variabler Größe 
einiger Felder durch Create erzeugen.

Es ist jedoch nicht notwendig, die Struktur wirklich anzulegen. Man 
berechnet einmal den benötigten Platz und reserviert nur einen 
"byte-Puffer". Dann ist kein Makro für Create:

Beispiel:
1
#define STRUCT_SIZE(n) (sizeof(myStruct_t) + sizeof(unsigned)*n)
2

3
static unsigned char buf_A[STRUCT_SIZE(50)];
4

5
    p_myA = CreateMyStruct(buf_A, sizeof(buf_A), "myA" );

Aufruf nur mit Speicher, Größe und Namen. CreateMyStruct erstellt dann 
aus Puffer und Größe per cast die Structur und rechnet size aus. Etwa 
so:
1
my_t * CreateStruct(unsigned char *b, size_t n, char *name)
2
{
3
const int   s = ; // Größe der Struktur in Bytes
4
myStruct_t *p = (myStruct_t *) b;   // Zeiger auf die Struktur
5
unsigned   *a = b + s;              // Zeiger auf das Array
6
size_t   size = n - s;              // Arraygröße in Byte   
7
    
8
     /* und aufruf Deiner Funktion wie bisher */
9
     return _CreateStruct(p, name, a, size/(sizeof unsigned)  );
10
}
Gast #6862193
Lesenswert?

W.S. schrieb:
> Wozu das Ganze?
> Ich bin da eher für klare Verhältnisse, wozu auch der Verzicht auf
> umfangreichere Macros gehört. ... Sowas ist bei
> gründlicher Denk-Vorarbeit sowohl einfacher zu schreiben als auch
> leichter zu warten. ...

Das könnte bei Macros wie sie im Linux Kernel oder Zephyr verwendet 
werden genau das gegentail bewirken.

Die macros dort ersparen den entwicklern jede menge fleis arbeit.
Ja das macro ist sehr komplex, teils nicht leicht zu versthehen.
Erspart dir aber jede menge copy past. Beim anlgen und gerade beim 
anpassen.

Es ist halt z.B. abzuwägen was besser ist, ein complexes Macro oder jede 
menge copy past code.
(Firma: fritzler-avr.de) #6862213
Lesenswert?

BLE schrieb:
> Es ist halt z.B. abzuwägen was besser ist, ein complexes Macro oder jede
> menge copy past code.

Bei W.S. ist die Antwort klar, er mag Kopierpastencode.
Auf Cortex-M mit mehreren uarts hat er für jeden Uart ne eigene Funktion 
mit verdoppeltem Code:
uart1_CharOut()
uart2_CharOut()
uart3_CharOut()
etc.

Bei Programmierfragen darf man nicht W.S. fragen.
Er kann ja nichtmal C.
Gast #6862301
Lesenswert?

A. S. schrieb:

> static unsigned char buf_A[STRUCT_SIZE(50)];

Das kann je nach Prozessor abstürzen oder auch nur unerwartete 
Ergebnisse liefern. Der zugrundeliegende Buffer braucht das maximale 
Alignment, das die zugrundeliegende Hardware kann (z.B. 4 Byte auf 
32bit-HW), und das muß man manuell als attribute zufügen.
Gast #6862317
Lesenswert?

Markus F. schrieb:
> Aha. Bring' dich mal auf Stand. Seit 21 Jahren kann man Konstanten
> definieren.

Nur liegen Konstanten beim AVR blöderweise im RAM. Sogar die avr_libc 
drängt zur Verwendung von #define für Konstante und konfigurierbare 
Parameter. Beispiele:

#define F_CPU 8000000
#define BAUD 9600

Wobei man das alternativ (als gcc Parameter -D) ins Makefile schreiben 
kann. Gerade bei F_CPU ist das der üblichere Weg.

Ich habe in drei Projekten umfangreiche Makros ausprobiert, die ganze 
Funktionen deklarieren. Und ich bin seit dem der Meinung, dass dies eine 
schlechte Idee war. Sie verbergen unnötig Details und führen im 
Fehlerfall zu hässlichen (oft unverständlichen) Fehlermeldungen des 
Compilers. Mehrfach verschachtelte Makros sind zudem extrem schwer 
verständlich.
Gast #6862327
Lesenswert?

BLE schrieb:
> Es ist halt z.B. abzuwägen was besser ist, ein complexes Macro oder jede
> menge copy past code.

Bleibe mal auf dem Teppich. Die Allermeisten, die hier fragen oder 
antworten, schreiben nicht an einem Linux-Kernel, sondern bauen eine 
Firmware für ihren Controller und das ist eine andere Liga.

Und wer in seiner Firmware für seinen kleinen Controller solche Dinge 
wie komplexe Macros benötigt, oder zu benötigen glaubt, der muß dann 
auch die Folgen davon tragen. Ich halte es da anders, nämlich die 
verschiedenen Ebenen in der Firmware voneinander getrennt zu halten, so 
daß man bei Plattformwechsel (z.B. von 78K5 auf FR30 und dann auf 
ARM7TDMI und von dort irgend etwas anders) nicht die eigentliche Logik 
anpassen muß, sondern lediglich zur jeweiligen Hardware passende 
Lowlevel-Treiber schreiben muß.

Das bleibt einem auch bei komplexen Macros nicht erspart, denn kein 
Macro kann die Spezifika einer Plattform vor-ahnen, worauf es noch nie 
portiert worden ist (weil diese Plattform erst nächstes Jahr erfunden 
werden wird)

W.S.
Gast #6862384
Lesenswert?

Nop schrieb:
> Das kann je nach Prozessor abstürzen oder auch nur unerwartete
> Ergebnisse liefern. Der zugrundeliegende Buffer braucht das maximale
> Alignment, das die zugrundeliegende Hardware kann (z.B. 4 Byte auf
> 32bit-HW), und das muß man manuell als attribute zufügen.

Ja. Stimmt. Gehört dazu.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren