[C] function prototype mit const pointer

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 527
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

[C] function prototype mit const pointer

Beitrag von starcow »

Abend zusammen :-)
Ich suche nach einer Erklärung, weshalb sich die Compiler (clang / gcc) nicht beschweren (auch kein Warning mit -pedantic -Wall -Wextra)
wenn man ihnen einen Funktionsprototypen serviert, der sich um ein const (bezogen auf den Pointer selbst) von der eigentlichen Funktion unterscheidet.

Code: Alles auswählen

void foo(int*);
void foo(int* const ptr){} // Prototyp von foo hat mich soeben angelogen
oder auch

Code: Alles auswählen

void foo(int* const);
void foo(int* ptr){} // Wieder gelogen...
bezieht sich das const jedoch auf den Typ, schlagen sie (beide) sofort Alarm. :-)
Es geht mir um plain C.
In C++ hätte man ja ohnehin die Möglichkeit, die Funktion entsprechend zu überladen (wobei ich mir hier auch nicht sicher bin, ob ein einzelnes const alleine zur Differenzierung ausreichen würde).
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von Krishty »

C++-Standard hat geschrieben:any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type
Den genauen Grund dafür kenne ich nicht, aber das const ist in diesem Fall Implementierungsdetail und kann dem Aufrufer der Funktion völlig egal sein. Es ändert ja nichts daran, wie die Funktion aufgerufen wird. Auch in C++ ist das keine Überladung, sondern ein und die selbe Funktion. So hätte ich es jedenfalls entschieden; ob das Komittee da andere Gründe hatte, weiß ich nicht.

Fun Fact: MSVC hat einen Bug, bei dem der Linker die Funktion nicht finden kann, wenn Deklaration und Definition in unterschiedlichen Translation Units liegen und nicht mindestens eine davon beide Versionen enthält. Das stört mich das seit … bestimmt einem Jahrzehnt mittlerweile :D Vor Jahren habe ich das mal gemeldet, und sie haben es für ganz exakt diesen einen Repro von mir gefixt, also int * – aber für literally jeden anderen Zeigertyp nicht. Bilderbuch-Support.

Edit: Mein erster Bug Report ging im Februar 2013 raus. Wirklich schon über ein Jahrzehnt. Wahnsinn.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 577
Registriert: 05.07.2003, 11:17

Re: [C] function prototype mit const pointer

Beitrag von Lord Delvin »

Zwei Thesen: Erstens betreffen die CV-Qualifier nur die Implementierung. Für die Verwendung sollte sich nichts verändern; wenn mich mein C-Wissen nicht schonwieder komplett verlassen hat ist das const an der Stelle bezogen auf den übergebenen Wert und nicht das was sich dahinter findet.
Zweitens, das ist für C jetzt wichtiger, sind joins auf Funktionstypen vollkommen nichttrivial und alles wird einfacher, wenn man Randfälle eliminert. Wenn man die cv-qualifier einfach immer streicht, sind mehr Dinge trivial kompatibel und es passiert öfter "was man denkt".
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von dot »

starcow hat geschrieben: 08.10.2023, 23:26 Ich suche nach einer Erklärung, weshalb sich die Compiler (clang / gcc) nicht beschweren (auch kein Warning mit -pedantic -Wall -Wextra)
wenn man ihnen einen Funktionsprototypen serviert, der sich um ein const (bezogen auf den Pointer selbst) von der eigentlichen Funktion unterscheidet.
Ein top-level const in einer Parameterdeklaration ist nicht Teil des Typs der Funktion:

Code: Alles auswählen

void fun(T);
und

Code: Alles auswählen

void fun(T const);
deklarieren dieselbe Funktion. Das const ist nur für den Typ des Parameters innerhalb des Body der Funktion relevant, nicht für den Typ oder die Signatur der Funktion an sich. [dcl.fct]/5

Alles Andere würde keinen Sinn machen. Die Argumente eines Funktionsaufrufes sind effektiv Initializer für die Parameter der Funktion. Der Caller einer Funktion hat über den Typ der Argumente keinen Einfluss auf ein solches const und könnte daher auch niemals zwischen Overloads basierend auf einem solchen const unterscheiden…
Benutzeravatar
starcow
Establishment
Beiträge: 527
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von starcow »

Ich danke euch, das leuchtet alles ein! Das const auf den Parameter selbst bezogen ist quasi eine "Interna" der Funktion, die für den Aufrufer an der Stelle völlig irrelevant ist.
Nach meinem Gefühl her, hätte ich jetzt ein solches const trotzdem in den Prototypen mit aufgenommen - einfach weil es sich sonst (ohne guten Grund) irgendwie "falsch" anfühlen würde.
Aber vielleicht habt ihr ein gutes Argument dafür, es im Prototypen tatsächlich wegzulassen.
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von dot »

starcow hat geschrieben: 10.10.2023, 17:16 Aber vielleicht habt ihr ein gutes Argument dafür, es im Prototypen tatsächlich wegzulassen.
Es ist für den Aufruf der Funktion irrelevant, in einem Prototypen also einfach nur Noise…
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von Krishty »

Dito. Wenn ich in der Definition ein const hinzufüge oder wegnehme, aus einem für den Aufrufer völlig irrelevanten Grund, möchte ich nicht jedes Mal in den Header gehen und das synchronisieren müssen. Und dann alles neu kompilieren.

Was in der Definition passiert, bleibt in der Definition.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Alexander Kornrumpf
Moderator
Beiträge: 2114
Registriert: 25.02.2009, 13:37

Re: [C] function prototype mit const pointer

Beitrag von Alexander Kornrumpf »

Wenn wir mal über den Tellerrand schauen, finde ich persönlich die syntaktisch am wenigsten verwirrende Option ist es überhaupt nie an Funktionsparameter zuzuweisen (damit sind "out" Parameter raus) und Tupel zurückzugeben (als Alternative zu besagten "out" Parametern). Ich glaube aber es gibt keine Sprache die das in dieser Kombination erzwingt.
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von Krishty »

Darum geht es nicht – void foo(int const x) hat nichts mit in-out-Parametern zu tun, sondern damit, ob der Funktionsrumpf seine lokale Kopie des Parameters verändern darf oder nicht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Alexander Kornrumpf
Moderator
Beiträge: 2114
Registriert: 25.02.2009, 13:37

Re: [C] function prototype mit const pointer

Beitrag von Alexander Kornrumpf »

Krishty hat geschrieben: 11.10.2023, 11:08 Darum geht es nicht – void foo(int const x) hat nichts mit in-out-Parametern zu tun, sondern damit, ob der Funktionsrumpf seine lokale Kopie des Parameters verändern darf oder nicht.
Es geht darum, dass ich im Funktionsrumpf nicht x=2 machen darf, as opposed to, wenn es ein komplexer Typ wäre, dass ich nicht x.y=2 machen darf, oder? Letzeres ist das "andere" const (eigentlich Mutability), das Java auf dieser Ebene nicht hat oder verwechsele ich die beiden jetzt schon wieder? [Ich finde diese Syntax dass const zwei Bedeutungen hat je nachdem wo es steht sehr schwer zu merken].

Wenn ich den Stil-Vorschlag mache "überhaupt nie an Funktionsparameter zuzuweisen" dann sind damit _auch_ "out-Parameter" (in C++ über Referenzen gelöst) unmöglich. Dass es in diesem konkreten Beispiel nicht darum ging hatte ich schon verstanden. Ich sagte ja "über den Tellerrand".
Benutzeravatar
starcow
Establishment
Beiträge: 527
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von starcow »

Interessanter Gedanke. Das würde aber dann bedeuten, dass ich Daten zur Bearbeitung nicht an eine andere Funktion übergeben könnte. Ich müsste immer zuerst alles kopieren (call by value), verändern und dann beim "Zurückgeben" nochmals kopieren. Auch beim Lesen, müsste ich immer alles zuerst kopieren. Ich kann mir nicht vorstellen, dass dies ohne Teils erhebliche Performanceverluste möglich wäre.

Bezüglich "const const"
Grundsätzlich bezieht sich das const immer auf den Ausdruck, der LINKS vom const steht. Falls links vom const nichts mehr steht, bezieht es sich auf den Ausdruck rechts von ihm - quasi als Ausnahme.
So Argumentiert, ist konsequenter, const immer RECHTS vom Ausdruck zu platzieren. Und ich glaube, das ist auch der Grund, wieso es Krishty so macht :-) (falls ich mich denn richtig erinnere!).

Code: Alles auswählen

int const * const ptr
Das erste const bezieht sich also auf den int, das zweite auf den Pointer (in Form des Sternchens!).
dot hat geschrieben: 11.10.2023, 02:00 Es ist für den Aufruf der Funktion irrelevant, in einem Prototypen also einfach nur Noise…
Ok, überzeugt! :-)
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Alexander Kornrumpf
Moderator
Beiträge: 2114
Registriert: 25.02.2009, 13:37

Re: [C] function prototype mit const pointer

Beitrag von Alexander Kornrumpf »

starcow hat geschrieben: 19.10.2023, 15:42 Interessanter Gedanke. Das würde aber dann bedeuten, dass ich Daten zur Bearbeitung nicht an eine andere Funktion übergeben könnte. Ich müsste immer zuerst alles kopieren (call by value), verändern und dann beim "Zurückgeben" nochmals kopieren. Auch beim Lesen, müsste ich immer alles zuerst kopieren. Ich kann mir nicht vorstellen, dass dies ohne Teils erhebliche Performanceverluste möglich wäre.
Auf C++ bezogen würde mein Vorschlag eigentlich bedeuten, dass Referenzparameter immer `const` sein sollten und man für den C++ Anwendungsfall von nicht konstanten Referenzparametern eine andere Syntax (tuple return) hätte, die C++ aber nicht hat. Es war nicht gemeint, dass man keine Referenzparameter mehr haben kann.

Der Grund dafür ist persönliche Präferenz bezüglich der genannten Metrik "am wenigsten verwirrend", YMMV. Aber wie gesagt C und C++ lassen dir die Wahl ja sowieso nicht.
Benutzeravatar
Krishty
Establishment
Beiträge: 8245
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von Krishty »

Alexander Kornrumpf hat geschrieben: 19.10.2023, 16:07Auf C++ bezogen würde mein Vorschlag eigentlich bedeuten, dass Referenzparameter immer `const` sein sollten und man für den C++ Anwendungsfall von nicht konstanten Referenzparametern eine andere Syntax (tuple return) hätte, die C++ aber nicht hat. Es war nicht gemeint, dass man keine Referenzparameter mehr haben kann.

Der Grund dafür ist persönliche Präferenz bezüglich der genannten Metrik "am wenigsten verwirrend", YMMV. Aber wie gesagt C und C++ lassen dir die Wahl ja sowieso nicht.
An dieser Stelle sei daran erinnert, dass C++ schief zusammengezimmerte Tupel hat. Nicht, dass ich empfehlen würde, sie zu benutzen (oder dass sie auch nur irgendein Problem lösen würden); aber starcow möchte ja immer gern etwas lernen.

Code: Alles auswählen

#include <tuple>
#include <cassert>

auto lol() {
    return std::make_tuple(123, -9.8f, nullptr);
}

int main() {
    auto [ integer, fp, pointer ] = lol();
    assert(integer == 123);
    assert(fp == -9.8f);
    assert(pointer == nullptr);
}
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von dot »

alternativ:

Code: Alles auswählen

auto lol()
{
    struct result { int integer; float fp; void* pointer; };
    return result { 123, -9.81f, nullptr };
}

int main()
{
    auto [integer, fp, pointer] = lol();
}
Alexander Kornrumpf
Moderator
Beiträge: 2114
Registriert: 25.02.2009, 13:37

Re: [C] function prototype mit const pointer

Beitrag von Alexander Kornrumpf »

Danke.
Benutzeravatar
starcow
Establishment
Beiträge: 527
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: [C] function prototype mit const pointer

Beitrag von starcow »

dot hat geschrieben: 20.10.2023, 01:19 alternativ:

Code: Alles auswählen

auto lol()
{
    struct result { int integer; float fp; void* pointer; };
    return result { 123, -9.81f, nullptr };
}

int main()
{
    auto [integer, fp, pointer] = lol();
}
Oh, gut zu wissen!
Krishty hat geschrieben: 19.10.2023, 23:30 aber starcow möchte ja immer gern etwas lernen.
:-) Danke Krishty! Du kennst mich tatsächlich :->
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Antworten