Forum: Compiler & IDEs C++ template Funktion doppelt definiert in header und cpp


von Johannes S. (Gast)


Lesenswert?

bei der Suche nach einem Problem in der Mbed SPI Funktion bin ich auf 
eine doppelte Definition einer Funktion gestossen. Es sieht für mich wie 
ein Fehler aus, der sich allerdings erstmal nicht auswirkt. Oder macht 
so etwas Sinn?
Ich kann auch den Code in SPI.cpp auskommentieren und es kompiliert und 
linkt ohne Fehler.

in SPI.h:
1
    template<typename Type>
2
    int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
3
    {
4
        if (spi_active(&_peripheral->spi)) {
5
            return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event);
6
        }
7
        start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event);
8
        return 0;
9
    }


und in SPI.cpp der gleiche Code, aber etwas andere Funktionssignatur:
1
int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event)
2
{
3
    if (spi_active(&_peripheral->spi)) {
4
        return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
5
    }
6
    start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
7
    return 0;
8
}

von Klaus W. (mfgkw)


Lesenswert?

Das erste ist ein template, das zweite nicht.

Die zweite Funktion passt nicht dazu, wegen der anderen Signatur 
(unsigned char bit_width) hat die nichts mit dem Template zu tun.
Gibt es noch mehr templates?

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

ja, danke, jetzt fällt der Grosche. Es gibt noch eine Deklaration die 
passt, nicht als template aber als Funktion:
1
    int transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event);

habe die Funktion jetzt so aufgerufen:
1
            // asynchronous transfer
2
            spi.transfer((const void*)tx_data, tx_word_len * sizeof(*tx_data),
3
                         (void*)rx_data, rx_word_len * sizeof(*rx_data), nullptr);

dann gibts natürlich Mecker wenn die Funktion fehlt.
Beim typisierten Bufferzeiger wird also die Größe automatisch richtig 
übergeben. Wenn man nicht blöderweise auf einen (char*) castet.

von Klaus W. (mfgkw)


Lesenswert?

Was willst du jetzt aufrufen eigentlich? Eine über das template 
definierte Funktion, oder eine der anderen?

von Johannes S. (Gast)


Lesenswert?

über das template, da lasse ich jetzt den type cast weg und dann ist das 
richtig. Oder mit (void*), dann muss aber die bit_length angegeben 
werden.

von Klaus W. (mfgkw)


Lesenswert?

Johannes S. schrieb:
> habe die Funktion jetzt so aufgerufen:            // asynchronous
> transfer
>             spi.transfer((const void*)tx_data, tx_word_len *
> sizeof(*tx_data),
>                          (void*)rx_data, rx_word_len * sizeof(*rx_data),
> nullptr);

Passt das irgendwie zum template?

Johannes S. schrieb:
> in SPI.h:    template<typename Type>
>     int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer,
> int rx_length, const event_callback_t &callback, int event =
> SPI_EVENT_COMPLETE)
>     {
>         ...
>     }

von Johannes S. (Gast)


Lesenswert?

ich habe es aktualisiert, ist nicht wie es zuerst oben stand:
1
        tx_word_len = 2;
2
        rx_word_len = 2;
3
4
    const uint16_t tx_data[8] = {0x1122, 0x3344}; // allocate extra memory to prevent "out of range" error
5
    uint16_t rx_data[8] = {0};
6
7
            spi.transfer(tx_data, tx_word_len * sizeof(*tx_data),
8
                         rx_data, rx_word_len * sizeof(*rx_data), nullptr);

das ist Teil von einem Testcode, deshalb die 'komische' Größenangabe.

von Klaus W. (mfgkw)


Lesenswert?

Trotzdem sehe ich immer noch kein Objekt für das callback.
Aber wenn es funktioniert, soll es mir recht sein.

von Johannes S. (Gast)


Lesenswert?

es funktioniert nicht, zumindest nicht mit einem H7, deshalb suche ich 
da, aber die Ursache muss eine andere sein.
Trotz 4 Augen hatte ich die zweite Deklaration im Header übersehen, habe 
da schon zu lange draufgestarrt.

der callback ist das 5. Argument in der template Funktion, der ist jetzt 
der nullptr und wird damit nicht aufgerufen. Das 6. ist ein event, das 
wird dem callback mitgegeben und ist default und uninteressant wenn der 
callback nicht aufgerufen wird.

Mit der Funktion im Header kommt der Debugger nicht gut klar, der hat 
mich da auch verwirrt.

Und das eigentliche Problem ist das SPI beim H7 das jetzt noch zickt. 
Jemand hatte den SPI Code angepackt und ein andere Problem beseitigt. 
Damit funktionierte aber SPI mit 16 Bit nicht mehr. Das konnte ich jetzt 
für STM32F4 beheben, aber der Test mit dem H7 zeigte wieder neue 
Probleme. Im H7 ist ein komplett neues SPI Device, das versteht man 
glaube ich nur wenn man das gleiche raucht wie die Entwickler.

Hoffe ich konnte genug verwirren und Danke nochmal für die Anteilnahme 
:)

von Blume (Gast)


Lesenswert?

Johannes S. schrieb:
> es funktioniert nicht, zumindest nicht mit einem H7, deshalb suche ich
> da, aber die Ursache muss eine andere sein.

Mit welchem H7 Board aebeitet ihr denn?
etwa mit dem Portenta?

von Klaus W. (mfgkw)


Lesenswert?

Johannes S. schrieb:
> der callback ist das 5. Argument in der template Funktion, der ist jetzt
> der nullptr und wird damit nicht aufgerufen.

Irgendwie fehlt noch etwas an der Geschichte...

Das callback ist doch als Referenz deklariert in der Parameterliste.
Wie kann man für eine Referenz einen nullptr übergeben?

Ich glaube nach wie vor, daß du was ganz anderes aufrufst, was du uns 
noch nicht gezeigt hast.

von Johannes S. (Gast)


Lesenswert?

Blume schrieb:
> Mit welchem H7 Board aebeitet ihr denn?

ich benutze dieses:
https://de.aliexpress.com/item/1005001683272407.html
war aber von einem anderen Händler.
sehe gerade 11000+ verfügbar, gute Quelle für die H743 :)

Klaus W. schrieb:
> Das callback ist doch als Referenz deklariert in der Parameterliste.
> Wie kann man für eine Referenz einen nullptr übergeben?

doch hat definitv funktioniert mit nullptr ohne Compilermecker, habe 
jetzt aber auch mal eine Funktion angegeben.
https://github.com/JojoS62/testSPI/commits/master/main.cpp
in dem commit davor ist noch der nullptr drin.

Das SPI Problem nach dem ich suchte war aber ein anderes, das SPI device 
im H7 und U5 ist ein anderes, neues als bei den älteren Serien. Das hat 
u.a. ein 'lock' feature, d.h. einige Einstellungen wie Direction lassen 
sich nicht ändern wenn SPI enabled ist. Da kann man herrlich nach 
Fehlern suchen.

von mh (Gast)


Lesenswert?

Johannes S. schrieb:
> doch hat definitv funktioniert mit nullptr ohne Compilermecker, habe
> jetzt aber auch mal eine Funktion angegeben.

Das ist unwahrscheinlich.

von Johannes S. (Gast)


Lesenswert?

was mache ich dann falsch?
Das wird in der Callback Klasse gehandhabt, fragt mich nicht wie. Ich 
bin froh das ich mittlerweile einen Callback benutzen kann, die 
Implementierung ist schon hardcore, da wurde schon ein paar Tage dran 
gearbeitet:
https://github.com/ARMmbed/mbed-os/blob/master/platform/include/platform/Callback.h

beim Aufruf eines Callback muss man auf ungleich nullptr prüfen, das 
wird hier auch gemacht:
1
    if (_callback && (event & SPI_EVENT_ALL)) {
2
        _set_ssel(1);
3
        unlock_deep_sleep();
4
        _callback.call(event & SPI_EVENT_ALL);
5
    }

Ich denke es funktioniert so: der nullptr ist keine Klasse 
event_callback_t und durch
1
using event_callback_t = Callback<void(int)>;
wird implizit eine Instanz Callback(nullptr) erzeugt, die ist definiert 
und damit dann auch eine gültige Referenz. Ist das so richtig?

von Oliver S. (oliverso)


Lesenswert?

Das using ist nichts anderes als ein typedef. Das definiert nur ein 
alias für einen Typ.

Oliver

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.