Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Referenzen werden nicht aufgelöst

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
21.02.2009, 11:29 Uhr
~Rucola
Gast


Hallo

Es geht gemischten Code C und C++. Um Daten vom C-Code in C++ Teil zu schreiben, sind in einem cpp - file globale Variablen definiert. In der C-Funktion sind diese Variablen definiert. Nun beim Linken findet der Linker die referenzierten Namen nicht. Was ist falsch?

Das Programm ist folgend aufgebaut. 2-3 *.cpp module. In einem Modul sind einige globale Variablen definiert.
Diese Variablen sind in dem ".c File referenziert.
Beim Linken meldet der Linker, dass er die referenzierten Variablen nicht finden kann.
Besteht eine inkompatibilität zwischen *.cpp und *.C file. Das Schlüsselwort " extern C" ist in den *.Cpp Filees enthalten.

Rucola
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
21.02.2009, 22:12 Uhr
0xdeadbeef
Gott
(Operator)


Da könnte ich ohne Code höchstens raten. Zeig am besten mal anhand eines kleinen Beispiels, was du da zu tun versuchst.

Ansonsten scheint mir aber generell die Praxis, da Datenaustausch über globale Variablen zu machen, höchst fragwürdig - immerhin können sich C- und C++-Code anstandslos aufrufen, sofern man die Linkage beachtet; globale Variablen sind bestenfalls ein sehr dreckiger Hack und schlimmstenfalls brandgefährlich.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
22.02.2009, 20:46 Uhr
~Rucola
Gast


Leider sind die Codesegmente, die ich mitschicken wollte, zu lang. Darum jetzt nur diesen Text.

Ich bin mir durchaus bewusst, dass diese Art der Programmierung nicht sehr elegant ist. Meine Absicht ist in einem Thread C-Code ( z.B. von einem Microcontroller) oder Teile davon laufen zulassen und im Hauptthread in einem Dialogfenster gewisse Variablen des Controllerprogramms anzuzeigen.
Bisher habe ich mühsam nur den Code Step by Step oder wenns gut geht mit Breakpoints abarbeiten und beobachten können, auch weil keine Ausgaben auf den Bildschirm möglich sind.

Nun aber zu meinem (Beispiel-)code. Ich habe übrigens beide Varianten ausprobiert: Die Definition der Variablen im cpp file und die Referenzierung im c-File und umgekeht. Es gibt beide male die gleichen Fehlermeldungen, Linkerfehler LNK2001.

Ich werde das Beispiel noch kürzen.


Rucola
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
23.02.2009, 08:11 Uhr
~Rucola
Gast


Hallo


C++:
// Nicht aufgelöste Referenzen zwischen cpp und C-Files. Siehe Fehlermeldung am Schluss.

//  Im Beispiel wird die Variable LowerPosition referenziert
//  case WM_DESTROY:
//    LowerPosition = 100;    // Test Referenzen extern unsigned long

// Files Referenz2.cpp, Referenz.c in einer einfachen Windows "Hello World!" Anwendung ohne MFC

//Das C-File wird ohne "Precompiled Header Files" compiliert. Sonst entsteht eine Fehlermeldung, dass kein Fileende gefunden würde.



// ************************************************************



// Referenz2.cpp : Definiert den Einsprungpunkt für die Anwendung.
//

#include "stdafx.h"
#include "resource.h"

#define MAX_LOADSTRING 100

// Globale Variablen:
HINSTANCE hInst;                    // aktuelle Instanz
TCHAR szTitle[MAX_LOADSTRING];                                // Text der Titelzeile
TCHAR szWindowClass[MAX_LOADSTRING];                                // Text der Titelzeile

// Vorausdeklarationen von Funktionen, die in diesem Code-Modul enthalten sind:
ATOM                MyRegisterClass( HINSTANCE hInstance );
BOOL                InitInstance( HINSTANCE, int );
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );
LRESULT CALLBACK    About( HWND, UINT, WPARAM, LPARAM );

//  externe Referenzen
extern unsigned long LowerPosition;        /* Lower Position         */


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
     // ZU ERLEDIGEN: Fügen Sie hier den Code ein.
    MSG msg;
    HACCEL hAccelTable;

    // Globale Zeichenfolgen initialisieren
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_REFERENZ2, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Initialisierung der Anwendung durchführen:
    if( !InitInstance( hInstance, nCmdShow ) )
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_REFERENZ2);

    // Hauptnachrichtenschleife:
    while( GetMessage(&msg, NULL, 0, 0) )
    {
        if( !TranslateAccelerator (msg.hwnd, hAccelTable, &msg) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }

    return msg.wParam;
}



//
//  FUNKTION: MyRegisterClass()
//
//  AUFGABE: Registriert die Fensterklasse.
//
//  KOMMENTARE:
//
//    Diese Funktion und ihre Verwendung sind nur notwendig, wenn dieser Code
//    mit Win32-Systemen vor der 'RegisterClassEx'-Funktion kompatibel sein soll,
//    die zu Windows 95 hinzugefügt wurde. Es ist wichtig diese Funktion aufzurufen,
//    damit der Anwendung kleine Symbole mit den richtigen Proportionen zugewiesen
//    werden.
//
ATOM MyRegisterClass( HINSTANCE hInstance )
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = LoadIcon(hInstance, (LPCTSTR)IDI_REFERENZ2);
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    = (LPCSTR)IDC_REFERENZ2;
    wcex.lpszClassName    = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

    return RegisterClassEx(&wcex);
}

//
//   FUNKTION: InitInstance(HANDLE, int)
//
//   AUFGABE: Speichert die Instanzzugriffsnummer und erstellt das Hauptfenster
//
//   KOMMENTARE:
//
//        In dieser Funktion wird die Instanzzugriffsnummer in einer globalen Variable
//        gespeichert und das Hauptprogrammfenster erstellt und angezeigt.
//
BOOL InitInstance( HINSTANCE hInstance, int nCmdShow )
{
   HWND hWnd;

   hInst = hInstance; // Instanzzugriffsnummer in unserer globalen Variable speichern

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if( !hWnd )
   {
      return FALSE;
   }

   ShowWindow( hWnd, nCmdShow );
   UpdateWindow( hWnd );

   return TRUE;
}

//
//  FUNKTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  AUFGABE:  Verarbeitet Nachrichten für das Hauptfenster.
//
//  WM_COMMAND    - Anwendungsmenü verarbeiten
//  WM_PAINT    - Hauptfenster darstellen
//  WM_DESTROY    - Beendigungsnachricht ausgeben und zurückkehren
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR szHello[MAX_LOADSTRING];
    LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

    switch( message )
    {
        case WM_COMMAND:
            wmId    = LOWORD(wParam);
            wmEvent = HIWORD(wParam);
            // Menüauswahlen analysieren:
            switch( wmId )
            {
                case IDM_ABOUT:
                   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
                   break;
                case IDM_EXIT:
                   DestroyWindow( hWnd );
                   break;
                default:
                   return DefWindowProc( hWnd, message, wParam, lParam );
            }
            break;
        case WM_PAINT:
            hdc = BeginPaint (hWnd, &ps);
            // ZU ERLEDIGEN: Hier beliebigen Code zum Zeichnen hinzufügen...
            RECT rt;
            GetClientRect( hWnd, &rt );
            DrawText( hdc, szHello, strlen(szHello), &rt, DT_CENTER );
            EndPaint( hWnd, &ps );
            break;
        case WM_DESTROY:
            LowerPosition = 100;    // Test Referenzen extern unsigned long
            PostQuitMessage( 0 );
            break;
        default:
            return DefWindowProc( hWnd, message, wParam, lParam );
   }
   return 0;
}

// Nachrichtenbehandlungsroutine für "Info"-Feld.
LRESULT CALLBACK About( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
    switch( message )
    {
        case WM_INITDIALOG:
                return TRUE;

        case WM_COMMAND:
            if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
            {
                EndDialog(hDlg, LOWORD(wParam));
                return TRUE;
            }
            break;
    }
    return FALSE;
}



/******************************************************************************
*
*  *************************************************************************
*  *                                                                       *
*  *    Hauptprogramm                                                      *
*  *                                                                       *
*  *************************************************************************
*
*  Filename...........  test1.c (spaeter main)
*  Modulname..........  Main
*  Uebersetzungsprogr.  TMS-370 C-Compiler
*  Abstammung.........  Original
*  Version............  %
*  Bearbeiter.........  Peter Federer
*  Datum..............  Apr-20-98  Fed  Kommentar ueberarbeitet
*
*  Freig: ..........                           Freig. Datum:  ...........
*------------------------------------------------------------------------------
*
*   *   ******  ************************************************************
*   *   *       *        Copyright (C) by                                  *
*   *   ****    *        Ingenieurbuero FEDERER                            *
*   *   *       *        Maennedorf Switzerland                            *
*   *   *       ************************************************************
*
*------------------------------------------------------------------------------
*  Modulbeschreibung:
*   Es handelt sich um das Hauptprogramm.
*
*    Moegliche Codeersparnis
*    -----------------------
*    - Tabellen in ICT kuerzen (keine Reserve)
*    - Fourier zusammenfassen
*
*    Debug-Stand
*    -----------
*    - Eine ICT-Routine maskiert
*    - Kalibrierung eingeschaltet
*    - Feste Parameter fuer Hubmessung = off
*
*    Letzte Ueberpruefungen
*    ----------------------
*    - Warum ist Pin 5 floatend ?
*    - PWM Start !
*    - Strom nachpruefen (Sigi) => Kurzgeschlossene Outputs (Masse)
*
*------------------------------------------------------------------------------
*  Aenderungen:
*  Version      Grund
*
******************************************************************************/


// Variablen zur Anzeige der EEPROM-Parameter
unsigned long LowerPosition;        /* Lower Position         */
unsigned long UpperPosition;        /* Upper Position         */
short         Gain;                 /* Gain  ursprüngliche Definition: BYTE */
unsigned long LowerSetpointU;       /* Lower Setpoint (voltage)  */
unsigned long UpperSetpointU;       /* Upper Setpoint (voltage)  */
unsigned long LowerSetpointI;       /* Lower Setpoint (current)  */
unsigned long UpperSetpointI;       /* Upper Setpoint (current)  */
unsigned long Checksum;             /* Check-Summe  EEPROM       */


void Referenzen(void)
{
    LowerPosition = 100;
    UpperPosition = 100;
}





Code:
Linker-Vorgang läuft...
Referenz2.obj : error LNK2001: Nichtaufgeloestes externes Symbol "unsigned long LowerPosition" (?LowerPosition@@3KA)
Debug/Referenz2.exe : fatal error LNK1120: 1 unaufgeloeste externe Verweise
Fehler beim Ausführen von link.exe.

Referenz2.exe - 2 Fehler, 0 Warnung(en)


Dieser Post wurde am 24.02.2009 um 10:09 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
23.02.2009, 08:28 Uhr
0xdeadbeef
Gott
(Operator)


Ich hatte mit einem kleinen Beispiel eigentlich schon ein möglichst kurz zusammengestrichenes Projekt gemeint, etwa

C++:
// header.h
#ifndef INCLUDED_HEADER_H
#define INCLUDED_HEADER_H

#ifdef __cplusplus
extern "C" {
#endif

extern unsigned long shared_var;

void tu_etwas_mit_shared_var(void);

#ifdef __cplusplus
}
#endif

#endif



C++:
// c_teil.c
#include "header.h"

unsigned long shared_var;

void tu_etwas_mit_shared_var(void) {
  shared_var = 100;
}



C++:
// cpp_teil.cc
#include "header.h"

#include <iostream>

int main() {
  tu_etwas_mit_shared_var();
  std::cout << shared_var << std::endl;
}


So oder so, ich finde in deinem Code nirgendwo ein extern "C", was mich vermuten lässt, dass der C-Teil ein nicht-dekoriertes Symbol exportiert, während der C++-Teil ein dekoriertes sucht. Mit einiger Wahrscheinlichkeit muss das einfach

C++:
// externe Referenzen
extern "C" unsigned long LowerPosition; /* Lower Position */


heißen.

Ganz generell aber...wäre es nicht sinnvoller, stattdessen ein struct herumzureichen? Es wäre auf jeden Fall flexibler, also beispielsweise

C++:
// eeprom_api.h
#ifndef INCLUDED_EEPROM_API_H
#define INCLUDED_EEPROM_API_H

#ifdef __cplusplus
extern "C" {
#endif

struct eeprom_params {
  unsigned long LowerPosition; /* Lower Position */
  unsigned long UpperPosition; /* Upper Position */
  short Gain; /* Gain ursprüngliche Definition: BYTE */
  unsigned long LowerSetpointU; /* Lower Setpoint (voltage) */
  unsigned long UpperSetpointU; /* Upper Setpoint (voltage) */
  unsigned long LowerSetpointI; /* Lower Setpoint (current) */
  unsigned long UpperSetpointI; /* Upper Setpoint (current) */
  unsigned long Checksum; /* Check-Summe EEPROM */
};

void Referenzen(struct eeprom_params *);

#ifdef __cplusplus
}
#endif

#endif



C++:
// C-Source
#include "eeprom_api.h"

void Referenzen(struct eeprom_params *p) {
  p->LowerPosition = 100;
  p->UpperPosition = 100;
}



C++:
// C++-Source
#include "eeprom_api.h"

#include <iostream>

int main() {
  eeprom_params ep;

  Referenzen(&ep);

  std::cout << ep.LowerPosition << ", " << ep.UpperPosition << std::endl;
}


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
24.02.2009, 08:57 Uhr
~Rucola
Gast


Danke. Hat mir sehr geholfen. Werde mir auch die eleganteren Ansätze noch anschauen.
Nun kann ich mich den nächsten Problemchen widmen.

Rucola
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: