C und globale Variablen

Hey,

was "neues" aus C. Ich habe mir folgendes gebaut, hier in Kurzform.

parameter.h
Code:
#ifndef PARAMETER
    #define PARAMETER
    #include <stdint.h>
    extern const uint32_t p[2];
#endif

parameter.c
Code:
#include "parameter.h"
const uint32_t p[2]={0xFF12345A, 0x3C};
void main(){}//<-- nötig?

und
test.c
Code:
#include "parameter.h"
void do(uint32_t A)
{
    A[0] += p[0];
    A[1] += p[1];
}

void main()
{
    uint32_t A[2] = {1,1};
    do(A);
}


Kompiliere ich nun nur die parameter.c mittels
Code:
arm-none-eabi-gcc parameter.c -o parameter.o
ist der Error
Code:
gnu-gcc/6 2017-q1-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit':exit.c:(.text.exit+0x2c): undefined reference to `_exit'collect2.exe: error: ld returned 1 exit status

Dabei spielt es keine Rolle, ob die Deklaration der Variablen innerhalb der main statt findet, oder nicht.

Die beiden *.o (test.o, parameter.o) werden am Ende gelinkt. Allerdings ist ja bereits zu sehen, dass die parameter.o nicht erzeugt wird.

Also: Was mache ich falsch?


Auch wenn ich die parameter.c vollständig in die parameter.h (natürlich ohne main..) kopiere und lösche, bekomme ich den Fehler:
Code:
test.c:(.text+0x2c): undefined reference to `p'
collect2.exe: error: ld returned 1 exit status
make: *** [test/test.elf] Error 1
 
Zuletzt bearbeitet:
Hi Shalec,

  1. Das p wird vom Compiler nicht gefunden, weil du es in der Header Datei als extern deklariert hast - damit sagst du dem Compiler, dass diese Variable irgendwo anders definiert ist, er kann sie aber leider nicht finden, da du eine völlig andere Datei kompilierst. Siehe dazu: Understanding "extern" keyword in C - GeeksforGeeks
  2. So wie ich das sehe möchtest du die Quelldateien einzeln in object files übersetzen. In dem Fall musst du den gcc folgendermaßen aufrufen:
    Code:
    gcc -o code.o -c code.c
    Wenn du das tust, muss die C Datei auch keine main Funktion enthalten. Andernfalls sagst du dem Compiler, dass du ein fertiges Programm nur aus dieser C-Datei erstellen möchtest, wozu du natürlich eine main Funktion brauchst.
  3. Deine test.c sieht ja gruselig aus! 8o Das ist sicher nur ein Formatierungsfehler, oder?

Viele Grüße,
Pik-9
 
Hi Shalec,

  1. Das p wird vom Compiler nicht gefunden, weil du es in der Header Datei als extern deklariert hast - damit sagst du dem Compiler, dass diese Variable irgendwo anders definiert ist, er kann sie aber leider nicht finden, da du eine völlig andere Datei kompilierst. Siehe dazu: Understanding "extern" keyword in C - GeeksforGeeks
So hatte ich es gestern bei stackexchange als Empfehlung gesehen, um damit dann versucht meine Probleme zu korrigieren.


2. So wie ich das sehe möchtest du die Quelldateien einzeln in object files übersetzen. In dem Fall musst du den gcc folgendermaßen aufrufen:
Code:
gcc -o code.o -c code.c
Wenn du das tust, muss die C Datei auch keine main Funktion enthalten. Andernfalls sagst du dem Compiler, dass du ein fertiges Programm nur aus dieser C-Datei erstellen möchtest, wozu du natürlich eine main Funktion brauchst.
Ah. Ok. Dann muss ich das in meiner Makefile mal hinzufügen. Die Option mit "-c" hatte ich ebenfalls gesehen, hatte aber den gleichen error. Mir würde es genügen, wenn ich die Variable in einer Header-File deklarieren könnte, sodass diese dann global zur Verfügung steht. (Also in allen eingebundenen Libs, allen C-Code usw.) Allerdings las ich, dass man das nicht in einer Header deklarieren sollte, sondern eher so machen sollte, wie ich es getan habe.



3. Deine test.c sieht ja gruselig aus! 8o Das ist sicher nur ein Formatierungsfehler, oder?

Jop. Ist es :D Dem Editor vom Board verschuldet. Ich versuche das mal zu korrigieren.

Was mir mal in C aufgefallen ist, man kann ja innerhalb eines Codes mittels {} Code-Blöcke eröffnen. Bei einigen Tests ist mir dabei aufgefallen, dass alle Variablen, die innerhalb eines solchen Blockes geschrieben wurden, nur darin gültig waren. Ist das Zufall gewesen, oder steckt da eine Theorie hinter?
Ich teste das gleich mal (später) und editiere hier ob es geklappt hat, oder nicht. Ggf. antworte ich auch hierauf.


Mir ist gerade in der Makefile aufgefallen, dass ich sowieso durch
Code:
%.o: %.c 
	$(ARMCC) $(CFLAGS) $(ARCH_FLAGS) -o $@ -c $<

die C-Files in einzelne Objekte übersetze. Daran wird es also nicht gelegen haben.
 
Zuletzt bearbeitet:
Das Problem war, dass meine Makefile die parameter.c nicht berücksichtigt hatte und es daher nicht mitcompiliert wurde :D

Danach musste ich in der Header die Deklarationen auf extern setzen und in der C ohne extern definieren.

dazu noch eine frage, wenn ich im header:

extern const int

declariere, kann ich dann in der C

static const int

definieren?

static bedeutet ja, dass eine Variable bis zum Ende des Programms existiert. Ist das überhaupt notwendig, wenn eine Variable außerhalb einer Funktion definiert wird? Ich habe mir das aus der FourQ-lib abgeguckt.


Btw. ich bin auf folgende Seite gestoßen und fand sie sehr übersichtlich, umfangreich und brauchbar:
C Data Types - C Programming - RapidTables.com
 
Zuletzt bearbeitet:
Danach musste ich in der Header die Deklarationen auf extern setzen und in der C ohne extern definieren.
Das extern ist in der Regel implizit, d.h. du musst es meistens gar nicht angeben, wenn du einfach eine Variable deklarieren willst, auf die du von allen Code Teilen Zugriff haben willst, die deine Header Datei per #include einbinden:
code.h
Code:
#ifndef CODE_H
#define CODE_H

const unsigned int xx;

#endif

code.c
Code:
#include "code.h"

const unsigned int xx = 3;

main.c
Code:
#include "code.h"

#include <stdio.h>

int main (int argc, char *argv[])
{
  printf ("var = %u\n", xx);
  return 0;
}

dazu noch eine frage, wenn ich im header:

extern const int

declariere, kann ich dann in der C

static const int

definieren?

static bedeutet ja, dass eine Variable bis zum Ende des Programms existiert. Ist das überhaupt notwendig, wenn eine Variable außerhalb einer Funktion definiert wird? Ich habe mir das aus der FourQ-lib abgeguckt.
Das Thema static hatten wir doch schon mal...
Eine variable als static zu deklarieren macht nur innerhalb eines Funktionsrumpfes Sinn. Global ist es bedeutungslos!

Und ja, die Sache mit den {} Blöcken innerhalb von Funktionen ist ein grundlegendes Konzept von C. Mit {} eröffnest du einen Scope, also einen Sichtbarkeitsbereich. Alle Variablen, Funktionen, etc, die du dort definierst/deklarierst sind nur dort sichtbar - das ist so vorgesehen. So ist z.B. jeder Rumpf einer if () {} Anweisung ein eigener Scope, in dem du Variablen definieren kannst, die nur in diesem einen Block sichtbar sind.

Viele Grüße,
Pik-9
 
Das Thema static hatten wir doch schon mal...
Eine variable als static zu deklarieren macht nur innerhalb eines Funktionsrumpfes Sinn. Global ist es bedeutungslos!
Ja hatten wir. Ich habe nur auch bei FourQ gespickt und das gefunden [1]. Ich suche dort noch deren Herangehensweise, um "mod p" auszuwerten. Bei der lib GMP bin ich nicht in der Lage den Code angemessen zu lesen.

Angenommen ich definiere eine der Variablen erst in einer Funktion und deklariere sie entsprechend mittels extern im header. Kann ich unter diesen Umständen "static" im "C" noch vorschalten?

Edit: Mir ist übrigens aufgefallen, dass in FourQ pauschal alles mit "static" deklariert/definiert wird. Hat das negative Auswirkungen?


[1] FourQlib/FourQ_params.h at master * Microsoft/FourQlib * GitHub
 
Zuletzt bearbeitet:
Neuer Punkt, der irgendwie hierzu passt.

Wenn ich irgendwo global
Code:
typedef  uint32_t type[16];
const type A;
definiert habe, und nun eine Funktion habe, die
Code:
void funktion( type A, type B, type C); //mache was mit A und B und speichere in C
erwartet. Nun möchte ich aber gerne
Code:
type B, C;
funktion (A,B,C);
ausführen. Dabei meckert mein Compiler und gibt mir eine Warnung aus.
Code:
from incompatible pointer type [-Wincompatible-pointer-types]
expected 'uint32_t * {aka long unsigned int *}' but argument is of type 'const uint32_t * {aka const long unsigned int *}'

Wie kann ich sowas sauber definieren? Die Eingabe wird immer ein passender typ sein. Muss ich einfach bei der Eingabe casten? Also (type) A beim Input schreiben?

Edit2: Das casten bringt einen anderen Fehler
Code:
type B, C;
funktion ((type)A,B,C);
führt zu
Code:
error: cast specifies array type

Allerdings führt ein Cast von
Code:
funktion ((uint32_t*)A,B,C);
zu keinem Error. Wird A dennoch korrekt übergeben? Im Grunde ist A selber ja nur ein Pointer. Also denke ich: Ja.
 
Zuletzt bearbeitet:
Zurück
Oben