Forum: Mikrocontroller und Digitale Elektronik kleines problem mit sizeof


von problemoSizeof (Gast)


Lesenswert?

Hallo,
ich habe ein kleines Problem mit dem sizeof.

Ich möchte eine c und h Datei anlegen für Ausgabenstrings.
1
c:
2
const char msg [] = " Hallo";
3
4
h:
5
extern const char msg [];
6
7
main.c:
8
9
size = sizeof(msg); // ---> Geht nicht
1
c:
2
const char msg [6] = " Hallo";
3
4
h:
5
extern const char msg [6];
6
7
main.c:
8
9
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?

von Karl H. (kbuchegg)


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
1
void foo( const char* text, int text_len )
2
{
3
  int i;
4
  for( i = 0; i < text_len; ++i )
5
    mach was mit text[i];
6
}

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

von problemoSizeof (Gast)


Lesenswert?

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

also gibt die header datei mit

extern const char msg [];

die info für sizeof nicht her.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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

von AKKS (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


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
1
extern const char msg [];
die Länge weißt, genausowenig weiß sie auch der Compiler. Der kann ja 
auch nicht zaubern :-)

von Nick M. (Gast)


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

von Karl H. (kbuchegg)


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)

von Nick M. (Gast)


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

von Karl H. (kbuchegg)


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.

von Nick M. (Gast)


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

von Nick M. (Gast)


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":
1
#ifndef __FOO_H__
2
#define __FOO_H__
3
  
4
  // was da rein soll
5
6
#endif

So werden multiple includes verhindert.


Gruß,
Nick

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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


So ließe sich das lösen:

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

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

// main.c
1
#include "bla.h"
2
3
wasauchimmer(msg, size);

von Karl H. (kbuchegg)


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":
>
1
> #ifndef __FOO_H__
2
> #define __FOO_H__
3
> 
4
>   // was da rein soll
5
> 
6
> #endif
7
>
>
> 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.

von Nick M. (Gast)


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

von Nick M. (Gast)


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

von Stefan E. (sternst)


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
1
const char msg[] = " Hallo";

datei_1.c
1
#include "msg.h

datei_2.c
1
#include "msg.h

=> msg im gesamten Programm 2 mal definiert.

von Nick M. (Gast)


Lesenswert?

> => msg im gesamten Programm 2 mal definiert.

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


Gruß,
Nick

von Stefan E. (sternst)


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.

von Karl H. (kbuchegg)


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.

von Nick M. (Gast)


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

von problemoSizeof (Gast)


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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das hat Karl Heinz gerade eben vor Deinem Posting getan.


@Karl Heinz:
> Dir scheint die Erkentniss zu fehlen

Bitte! Nicht sowas!

von Stefan E. (sternst)


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.

von Karl H. (kbuchegg)


Lesenswert?

>
> Bitte! Nicht sowas!

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

von Naja (Gast)


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:
1
#define MSG "Dies ist eine Nachricht"
2
#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:
1
const char msg [] = MSG;

schreiben.

Hilft das was?

von problemoSizeof (Gast)


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

von Nick M. (Gast)


Lesenswert?

> Autsch. Mea culpa

Kein Problem, ist schon nicht falsch angekommen.

Zu meiner Erkentniserweiterung muss ich das wohl einfach ausprobieren.


Gruß,
Nick

von Stefan E. (sternst)


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.

von Nick M. (Gast)


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

von Stefan E. (sternst)


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.

von Karl H. (kbuchegg)


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.

von problemoSizeof (Gast)


Lesenswert?

An Naja

> Hilft das was?

Danke Super hatte es noch nicht gelesen.

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.