mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik kleines problem mit sizeof


Autor: problemoSizeof (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe ein kleines Problem mit dem sizeof.

Ich möchte eine c und h Datei anlegen für Ausgabenstrings.
c:
const char msg [] = " Hallo";

h:
extern const char msg [];

main.c:

size = sizeof(msg); // ---> Geht nicht
c:
const char msg [6] = " Hallo";

h:
extern const char msg [6];

main.c:

size = sizeof(msg); // ---> OK
Doch das abzählen der Message ist ziemlich unkomfortabel bei Änderungen.
Kann man das erste Beispiel dem compiler irgend wie schmackhaft machen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
problemoSizeof schrieb:

> Kann man das erste Beispiel dem compiler irgend wie schmackhaft machen?

Nicht mit sizeof.
In diesem Fall musst du strlen benutzen, so wie bei jedem anderen 
String, von dem du die Länge nicht kennst.
Oftmals kann man aber auch ganz einfach die Tatsache ausnutzen, dass das 
letzte Byte des Strings '\0' enthält und seine Schleifen so formulieren, 
dass man die Länge gar nicht braucht.

Anstelle von
void foo( const char* text, int text_len )
{
  int i;
  for( i = 0; i < text_len; ++i )
    mach was mit text[i];
}

schreibt man ganz einfach (sinngemäss)
void foo( const char* text )
{
  while( *text != '\0' ) {
    mach was mit *text;
    text++;
  }
}
und schon benötigt niemand mehr die Textlänge :-)

Autor: problemoSizeof (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Info,
leider braucht eine fertige Betriebssystemfunktion die länge.
main.c:
const char msg [] = " Hallo";
size = sizeof(msg); // ---> OK

also gibt die header datei mit

extern const char msg [];

die info für sizeof nicht her.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tja, dann wirst Du wohl strlen verwenden müssen. Wie oft soll denn 
Deine "Betriebssystemfunktion" aufgerufen werden?

Autor: AKKS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
mach doch ein Define für die Länge.
Dann gibts keine Probleme beim abändern.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
problemoSizeof schrieb:

> also gibt die header datei mit
>
> extern const char msg [];
>
> die info für sizeof nicht her.

Nein.
sizeof wird zur Compiletime ausgewertet. Und genausowenig wie du bei
extern const char msg [];
die Länge weißt, genausowenig weiß sie auch der Compiler. Der kann ja 
auch nicht zaubern :-)

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss der string im .c-file sein? Im header wenn er ist gehts nämlich.
sizeof wird zur compile-Zeit ermittelt und darum muss der string dann 
auch bekannt sein. Ist er aber nicht, da er nicht im header steht.


HTH,
Nick

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:
> Muss der string im .c-file sein? Im header wenn er ist gehts nämlich.

Leider ist genau das das Problem
(Zumindest dann, wenn man nicht die gcc-Linker Erweiterung benutzen 
will)

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Leider ist genau das das Problem

Ich versteh nicht, warum das so sein muss, ich kenn mich mit dem gcc 
aber auch nicht aus.
Alternativ ginge es auch evtl. über ein #define Dann stehts aber auch 
wieder im header.


Gruß,
Nick

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:
>> Leider ist genau das das Problem
>
> Ich versteh nicht, warum das so sein muss, ich kenn mich mit dem gcc
> aber auch nicht aus.

Das Problem ist, dass das hier

extern const char msg[] = "Hallo Welt";

keine Deklaration ist (wie man durch das extern meinen könnte) sondern 
eine Definition. Durch die Initialisierung wird das extern ignoriert.

Gibt man obiges also in ein Header File, und inkludiert dieses in a-c 
und in b.c, so hat man 2 Definitionen von msg im System. Nach dem 
Buchstaben des Gesetzes ist das aber ein No-No.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> extern const char msg[] = "Hallo Welt";

Ja, natürlich gehts genau so nicht. Aber muss das denn extern sein?
Er will das Problem ja irgendwie gelöst haben.

Sorry für das Misverständnis. Ist mir schon klar, dass der string zur 
compile-time vorliegen muss.


Gruß,
Nick

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:

> Gibt man obiges also in ein Header File, und inkludiert dieses in a-c
> und in b.c, so hat man 2 Definitionen von msg im System. Nach dem
> Buchstaben des Gesetzes ist das aber ein No-No.


Naja, alter hut:

Header-file "foo.h":
#ifndef __FOO_H__
#define __FOO_H__
  
  // was da rein soll

#endif

So werden multiple includes verhindert.


Gruß,
Nick

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist zwar richtig, löst aber das Problem des Threadstarters nicht.


So ließe sich das lösen:

// bla.c
const char msg[] = " Hallo";
const int size = sizeof(msg);

// bla.h
extern const char msg[];
extern const int size;

// main.c
#include "bla.h"

wasauchimmer(msg, size);

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:
> Nachtrag:
>
>> Gibt man obiges also in ein Header File, und inkludiert dieses in a-c
>> und in b.c, so hat man 2 Definitionen von msg im System. Nach dem
>> Buchstaben des Gesetzes ist das aber ein No-No.
>
>
> Naja, alter hut:
>
> Header-file "foo.h":
>
> #ifndef __FOO_H__
> #define __FOO_H__
> 
>   // was da rein soll
> 
> #endif
> 
>
> So werden multiple includes verhindert.

Die helfen dir in diesem Fall nicht :-)

Include Guards sind nur dann eine Hilfe, wenn dasselbe #include in einer 
Compilation Unit auftaucht.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das ist zwar richtig, löst aber das Problem des Threadstarters nicht.

Natürlich löst es das Problem, ausser er besteht darauf es so zu machen 
wie es nicht geht. :-)
Er könnte evtl. mal erklären, warum er den string unbedingt in den 
implementation-file stecken will. Das ist nämlich ein Widerspruch: 
Einesteils versteckt er ihn, anderenteils soll er von aussen zugänglich 
sein. Also was nun?

Das "extern" ist sowieso eher ein 4-letter-word (mit 5 Buchstaben).


Gruß,
Nick

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die helfen dir in diesem Fall nicht :-)

Dann muss ich zugeben, dass ich das Problem überhaupt nicht verstehe.

Ohne das "extern" und dem string in einem header:
Wie muss das aussehen, dass es nicht funktioniert?

MMn bringt man das immer zum compilieren. Ausser mit "extern", da sind 
wir uns einig.


Gruß,
Nick

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:

> Dann muss ich zugeben, dass ich das Problem überhaupt nicht verstehe.
>
> Ohne das "extern" und dem string in einem header:
> Wie muss das aussehen, dass es nicht funktioniert?

msg.h
const char msg[] = " Hallo";

datei_1.c
#include "msg.h

datei_2.c
#include "msg.h

=> msg im gesamten Programm 2 mal definiert.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> => msg im gesamten Programm 2 mal definiert.

Wurde schon beantwortet, such mal hier nach "#ifndef".


Gruß,
Nick

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:
>> => msg im gesamten Programm 2 mal definiert.
>
> Wurde schon beantwortet, such mal hier nach "#ifndef".

Und es wurde ebenso schon beantwortet, dass dein Include-Guard dieses 
Problem nicht löst.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:
>> => msg im gesamten Programm 2 mal definiert.
>
> Wurde schon beantwortet, such mal hier nach "#ifndef".

Dir scheint die Erkentniss zu fehlen, dass der Compiler, wenn er 
datei_2.c compiliert, wieder bei 0 anfängt. Welche Erkentnisse oder 
#define er beim compilieren von datei_1.c gewonnen hat, wird zu Schall 
und Rauch sobald er sich datei_2.c vornimmt.
Und damit hilft dir zwar ein Include Guard wenn es darum geht mehrfache 
Defintionen in datei_1.c zu bekämpfen. Aber sie helfen nicht Probleme zu 
lösen, die dadurch entstehen, dass ein include File in datei_1.c UND 
datei_2.c inkludiert wird. Aus Compilersicht haben die beiden nichts 
miteinander zu tun. Insbesondere ist es völlig egal, welche #define beim 
compilieren von datei_1.c gemacht wurden. Sobald der fopen für datei_2.c 
erfolgt ist, sind die alle wieder verschwunden.


Es ist ein wesentliches Prinzip von C, dass jede *.c für sich alleine, 
ohne Ansehen aller anderen *.c die zum Projekt gehören, compiliert wird.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Und es wurde ebenso schon beantwortet, dass dein Include-Guard dieses
> Problem nicht löst.

Dann bitte ich höflichst um ein Beispiel. Kann ja durchaus sein, dass 
ich falsch liege. Dann möchte ich aber ungerne dumm sterben.


Gruß,
Nick

Autor: problemoSizeof (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Danke an alle,
da habe ich ja was losgetreten.

Ich mache es jetzt über ein zusätzliches #define im header und zähle die 
Zeichen.

Ich möchte die Ausgaben per Compilerschalter für verschiedene Sprachen 
haben.
Die verwendeten Ausgabestrings sind jetzt über mehrere Dateien verteilt.

Um bei einer Änderung auf eine neue Sprache nicht wieder alle Files 
durchsuchen zu müssen habe ich mich für den Weg mit einem extra c file 
entschieden.

mfg

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hat Karl Heinz gerade eben vor Deinem Posting getan.


@Karl Heinz:
> Dir scheint die Erkentniss zu fehlen

Bitte! Nicht sowas!

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:

> Dann bitte ich höflichst um ein Beispiel.

Das oben ist doch das Beispiel.
Und Karl-Heinz hat erklärt, wo dein Denkfehler ist.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>
> Bitte! Nicht sowas!

Autsch. Mea culpa
Kann nur sagen: Es ist Montag und ich hatte noch nicht viel Kaffee.

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht habe ich den Kick an dem Problem ja nicht mitbekommen, aber 
zumindest das zählen kann der Präprozessor für Dich erledigen.

In einer H-Datei:
#define MSG "Dies ist eine Nachricht"
#define MSG_LENGTH (sizeof(MSG) - 1)

Stringliterale kann man mit sizeof nämlich schon zählen.
(Da gab es hier auch mal einen Thread).

Dann kannst Du in einer C-Datei auch:
const char msg [] = MSG;

schreiben.

Hilft das was?

Autor: problemoSizeof (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal,
ich glaube diese von  Rufus t. Firefly vorgeschlagene lösung ist die 
beste

So ließe sich das lösen:

// bla.c

const char msg[] = " Hallo";
const int size = sizeof(msg);

// bla.h

extern const char msg[];
extern const int size;

// main.c

#include "bla.h"

wasauchimmer(msg, size);

besten dank

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Autsch. Mea culpa

Kein Problem, ist schon nicht falsch angekommen.

Zu meiner Erkentniserweiterung muss ich das wohl einfach ausprobieren.


Gruß,
Nick

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:
> Zu meiner Erkentniserweiterung muss ich das wohl einfach ausprobieren.

Dann vergiss aber nicht, dem Linker ein "--warn-common" mitzugeben, 
ansonsten schluckt er dieses "No-No" nämlichen kommentarlos (aus 
historischen Gründen).
Oder alternativ (und vielleicht besser): dem Compiler die Option 
-fno-common mitgeben.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Dann vergiss aber nicht, dem Linker ein "--warn-common" mitzugeben,

Wie gesagt, ich kenn mich mit dem gcc nicht aus (hab ihn nicht mal), und 
weiß daher auch nicht, was das --warn-common bewirkt.

Dass der string als symbol in beiden obj steht (aus a.c und b.c) ist 
klar. MMn darf sich der linker daran aber nicht stören, denn erst zum 
linken wird den symbols Speicherplatz zugewiesen und die Adressen darauf 
im obj aufgelöst. Dass ein und das selbe symbol in mehreren objs 
referenziert wird ist ja nur natürlich und kein Grund zum Meckern 
solange das der gleiche typ ist.

Naja, ich probiers aus und schau mir den map-file an.


Entspannter Gruß!
Nick

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:

> MMn darf sich der linker daran aber nicht stören, denn erst zum
> linken wird den symbols Speicherplatz zugewiesen und die Adressen darauf
> im obj aufgelöst. Dass ein und das selbe symbol in mehreren objs
> referenziert wird ist ja nur natürlich und kein Grund zum Meckern
> solange das der gleiche typ ist.

Es wird dann aber nicht nur das selbe Symbol referenziert, sondern auch 
definiert. Das ist ja das, was nicht passieren darf und warum es das 
"extern" auch überhaupt gibt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nick Müller schrieb:

> klar. MMn darf sich der linker daran aber nicht stören,

Doch, er darf.

> denn erst zum
> linken wird den symbols Speicherplatz zugewiesen

Und der Linker findet in den einzelnen Object Files mehrere 
Speicheranforderungen, die alle denselben Namen tragen. Und dann darf er 
sich daran stören :-)

> im obj aufgelöst. Dass ein und das selbe symbol in mehreren objs
> referenziert wird ist ja nur natürlich und kein Grund zum Meckern
> solange das der gleiche typ ist.

Das sieht der C-Standard aber anders :-)
Aber wie gesagt: Im gcc Linker ist eine Erweiterung eingebaut, die so 
etwas erlaubt.

Autor: problemoSizeof (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
An Naja

> Hilft das was?

Danke Super hatte es noch nicht gelesen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.