Sind Symbole aus der C-Standardbibliothek in C++ reserviert?

Lesezeit: 5 Minuten

Benutzer-Avatar
Serge Ballesta

Dies ist eine Fortsetzung einer anderen Frage.

Die ursprüngliche Frage hatte andere Probleme, aber ich musste erkennen, dass die Hauptfrage (laut CLang) a war Neudefinition von time als anderes Symbol während nur Hübsch Es wurden C++-Includes verwendet.

Hier also eine abgespeckte Version:

#include<iostream>

using std::cout;
using std::endl;

class time
{
public:
    int h, min, sec;
};

const int full = 60;

void canonify(time& pre)     // Error here (line 14)
{
    pre.min += pre.sec / full;
    pre.h += pre.min / full;
    pre.sec %= full;
    pre.min %= full;
}
int main()
{
    time a;                  // and here (line 23)
    a.h = 3;
    a.min = 128;
    a.sec = 70;
    canonify(a);
    cout << a.h << ":" << a.min << ":" << a.sec << endl;
}

Natürlich ersetzen time mit einem anderen Symbol oder mit struct time reicht um das Problem zu beseitigen. Anders gesagt meine Frage ist nicht wie man den Code zum Laufen bringt, sondern nur ob wir Symbole aus der C-Bibliothek als sehen müssen reservierte Token in C++. Clang 11 (auf MSVC19) drosselt mit:

1>ess.cpp(14,15): error : must use 'class' tag to refer to type 'time' in this scope
1>...\ucrt\time.h(518,42): message : class 'time' is hidden by a non-type declaration of 'time' here
1>ess.cpp(23,5): error : must use 'class' tag to refer to type 'time' in this scope
1>...\ucrt\time.h(518,42): message : class 'time' is hidden by a non-type declaration of 'time' here

Die Frage ist also: Wo verbietet der C++-Standard die freie Verwendung von Symbolen aus der C-Standardbibliothek, wenn sie nicht explizit in einer Kompilierungseinheit enthalten sind?


Interessanterweise funktioniert derselbe Code (einmal übersetzt …) in C einwandfrei:

#include <stdio.h>

//
typedef struct 
{
    int h, min, sec;
}time;
//
const int full = 60;
//
void canonify(time* pre)
{
    pre->min += pre->sec / full;
    pre->h += pre->min / full;
    pre->sec %= full;
    pre->min %= full;
}
int main()
{
    time a;
    a.h = 3;
    a.min = 128;
    a.sec = 70;
    canonify(&a);
    printf("%d:%d:%d\n", a.h, a.min, a.sec);
    return 0;
}

  • stackoverflow.com/questions/37589226/… Das scheint mir ein Dupe zu sein, aber ich bin nicht zuversichtlich, meinen Dupe-Hammer zu benutzen.

    – Bolov

    20. Juli 2021 um 12:42 Uhr


  • Der globale Namensraum ist sehr mit Bezeichnern verschmutzt. Titus Winters nannte es den wilden Westen. Es ist Ihrem Code nicht untersagt, Symbole im globalen Namensraum aus der C-Standardbibliothek zu verwenden. Das Einschließen der C++-verpackten C-Header-Dateien ist nicht verpflichtet, die C-Symbole im globalen Namensraum bereitzustellen (aber die meisten von ihnen tun dies – die meisten, aber nicht alle), unabhängig davon, ob sie es sind reserviert.

    – Eljay

    20. Juli 2021 um 12:46 Uhr


  • @bolov: Es ist tatsächlich das gleiche Problem. Aber die Sprache-Anwalt-Tag fragen Antworten mit präzisem Bezug auf die Norm. Aber ich muss zugeben, dass ich die andere Frage zuerst gefunden hätte, hätte ich diese nicht gestellt 😉

    – Serge Ballesta

    20. Juli 2021 um 12:56 Uhr

  • Zu Ihrer Information, std::endl ist hier völlig überflüssig. Rückkehr von main wird spülen std::cout. Und im Allgemeinen besteht normalerweise keine Notwendigkeit, im Rahmen des Druckens eine Spülung zu erzwingen '\n' – cout ist normalerweise bereits zeilengepuffert, wenn dies nützlich ist (dh wenn stdout ein TTY ist).

    – Peter Cordes

    21. Juli 2021 um 0:55 Uhr

  • Der Grund, warum Ihre Übersetzung nach C funktioniert, ist der C-Standard verbietet Header der C-Standardbibliothek sollen sich gegenseitig einschließen (mit einem kleinen und dokumentierten Satz von Ausnahmen), während der C++-Standard erlaubt Header der C++-Standardbibliothek, die sich gegenseitig einschließen. So iostream kann Symbole aus exponieren und tut dies auch ctimeaber stdio.h, wenn es als C kompiliert wirdkann nicht Symbole ausstellen time.h.

    – zol

    21. Juli 2021 um 13:16 Uhr

[extern.names]

3 Jeder Name aus der C-Standardbibliothek, der mit externer Verknüpfung deklariert ist, ist für die Implementierung zur Verwendung als Name mit externer “C”-Verknüpfung reserviert, sowohl im Namensraum std als auch im globalen Namensraum.

Beachten Sie, dass dieser Absatz den Namen selbst reserviert. Also Aliasing time im globalen Namensraum verstößt gegen diesen Vertrag.

  • Die Lösung besteht darin, Ihre eigenen zu wickeln time in deinem eigenen namespace.

    – Eljay

    20. Juli 2021 um 12:48 Uhr

  • @Eljay – Unter dem Vorbehalt dürfen Sie dafür keine C-Sprachverknüpfung verwenden.

    – StoryTeller – Unslander Monica

    20. Juli 2021 um 12:50 Uhr

  • @Eljay Was man immer für jede Deklaration tun sollte (außer für diesen einen Namensraum und Dinge wie main. Und ich nehme an, sprachübergreifende Schnittstellen.)

    – Erorika

    20. Juli 2021 um 12:52 Uhr


  • Danke, diesen Hinweis konnte ich nicht finden. Aber die Anzahl der Symbole in der C-Standardbibliothek ist laaaarund ich würde erwarten, dass viele Programmierer sie nicht alle kennen …

    – Serge Ballesta

    20. Juli 2021 um 12:54 Uhr

  • @SergeBallesta – Vorsichtige Verwendung von Namespaces vermeidet das Problem, wie bereits erwähnt. Zumindest haben Sie Rückgriff auf C++. C macht so ziemlich das Gleichestützt sich jedoch eher auf Konventionen als auf einen Sprachmechanismus, um Kollisionen zu vermeiden.

    – StoryTeller – Unslander Monica

    20. Juli 2021 um 12:57 Uhr

Wo verbietet der C++-Standard die freie Verwendung von Symbolen aus der C-Standardbibliothek?

Letzter Entwurf:

[extern.names]

Jeder Name aus der C-Standardbibliothek, der mit externer Verknüpfung deklariert ist, ist für die Implementierung zur Verwendung als Name mit externer “C”-Verknüpfung reserviert, sowohl im Namensraum std als auch im globalen Namensraum.

Jede Funktionssignatur aus der C-Standardbibliothek, die mit externer Verknüpfung deklariert ist, ist für die Implementierung zur Verwendung als Funktionssignatur mit externer “C”- und externer “C++”-Verknüpfung oder als Name des Namespace-Bereichs im globalen Namespace reserviert.


wenn sie nicht explizit in einer Übersetzungseinheit enthalten sind?

Wenn Sie die Standardbibliothek überhaupt verwenden, gelten alle Namensreservierungen der Standardbibliothek.

Wenn Sie einen Standardheader einfügen (oder einen Header, dessen genauen Inhalt Sie nicht kontrollieren und der daher Standardheader enthalten kann), schließen Sie möglicherweise indirekt andere Standardheader ein, einschließlich der von C geerbten.

1383030cookie-checkSind Symbole aus der C-Standardbibliothek in C++ reserviert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy