2013-10-25 6 views
16

Sto utilizzando solo i file di intestazione specifici per C++ (ad esempio <cstdlib>), tuttavia ottengo comunque funzioni dichiarate globalmente e non solo funzioni nello spazio dei nomi std. C'è un modo, forse un interruttore del compilatore, per impedirlo?Impedire funzioni standard al di fuori dello spazio dei nomi std

Ad esempio, il codice seguente:

#include <cstdlib> 
float random() { return 0.0f; } 
int main() { return 0; } 

FAIL compilare sotto Linux, con il seguente errore:

> g++ -c main.cpp main.o 
main.cpp: In function ‘float random()’: 
main.cpp:2:14: error: new declaration ‘float random()’ 
/usr/include/stdlib.h:327:17: error: ambiguates old declaration ‘long int random()’ 

o

> clang++ main.cpp -o main.o 
main.cpp:2:7: error: functions that differ only in their return type cannot be overloaded 
float random() { return 0.0f; } 
/usr/include/stdlib.h:327:17: note: previous declaration is here 
extern long int random (void) __THROW; 

che è causato che stdlib.h " inquina "il namespace globale con la sua funzione random.

Nota che non sto affrontando questi problemi durante la compilazione su Windows, utilizzando Visual Studio.

+1

Si noti che 'random' è ** non ** parte della libreria standard C. Questo non vuol dire che il problema non sia reale. –

+0

@PeteBecker Infatti, viene [da POSIX] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/random.html). Rende le cose anche degne di valore, non si deve solo prestare attenzione ai nomi standard C, ma anche a tutti gli oggetti POSIX. :( –

risposta

10
  1. <cstdlib> sarà sempre popolare namespace std, e talvolta definire simboli globali, mentre <stdlib.h> sarà sempre definire simboli globali, e talvolta popolano namespace std. Questo varia da implementazione a implementazione.

  2. Lo standard scrive:

    Every C header, each of which has a name of the form name.h , behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope. It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).

    Il che significa, che il compilatore è consentito per mettere quei simboli in ambito globale e std namespace allo stesso tempo.

  3. Pertanto, non vediamo alcun vantaggio nel preferire un file di intestazione rispetto all'altro. Poiché è possibile che lo sia in grado di inquinare l'ambito globale.

    Tuttavia, è ancora necessario utilizzare std spazio dei nomi quando #include <cstdlib>, e non usare std quando #include <stdlib.h>, per assicurarsi che il codice può compilare per tutte le implementazioni del compilatore.

  4. Avviso: Non utilizzare i nomi nelle librerie standard. Innanzitutto, non sono garantiti per funzionare. (Nota: Poche implementazioni del compilatore mantengono l'ambito globale pulito quando si usa #include <csomething>, quindi non si deve mai dipendere da questo.) In secondo luogo, confonderà lettori di codice e manutentori, perché quasi tutti supporteranno che i nomi standard siano effettivamente standard, indipendentemente da dove provengono .

+2

BTW, C++ 98 non ha permesso il '' per inquinare lo spazio dei nomi globale, C++ ha introdotto l'autorizzazione perché molte implementazioni avevano difficoltà a soddisfare il requisito (è molto difficile o impossibile da fare se non si controlla anche la libreria C mi sembra di ricordare un articolo del libstdC++ che descrive queste difficoltà, ma non lo trovo ora). – AProgrammer

6

È possibile dichiarare le proprie funzioni nei propri spazi dei nomi per impedire la collisione di dichiarazione.

namespace MyFunc 
{ 
float random() { return 0.0f; } 
}; 
+0

Sono d'accordo, è un buon walk-around, e una buona pratica di codifica in generale per mantenere il progetto in uno spazio dei nomi separato in primo luogo.Tuttavia, sto lavorando con un codice già in uscita, cercando di effettuare il porting da Windows a Linux e non voglio cambiare più di quanto sia assolutamente necessario – CygnusX1

0

in genere preferirei mantenere i nomi delle funzioni diversi da quelli definiti standard. Per ex qui si potrebbe usare il nome della funzione come myRandom anziché random in modo da poter informare le persone, che manterrebbero il mio codice in seguito, che la funzione utilizzata NON è quella definita come standard.

2

Lo standard consente esplicitamente alle intestazioni <c???> di portare i nomi delle funzioni standard C nello spazio dei nomi globale.

+3

A mio parere, mettere i nomi nello spazio dei nomi globale vanifica lo scopo di avere lo spazio dei nomi 'std' in primo luogo. Suppongo che questo permesso sia per la retrocompatibilità. Si noti che lo standard consente, ma non richiede, quindi potrebbe ancora esserci un interruttore che lo disattiva – CygnusX1

+1

Qualunque sia la ragione, lo standard fa quello che fa, e di conseguenza il codice portatile non deve avere conflitti di nome con le funzioni C. –

3

In generale si dovrebbe cercare di evitare la ridichiarazione in primo luogo. È possibile farlo utilizzando gli spazi dei nomi o suddividendo la sorgente in file che possono includere cstdlib e altri che possono utilizzare una versione static della funzione (denominazione in conflitto).

Se questa non è un'opzione, continua a leggere. Ma tieni presente che quanto segue potrebbe essere molto specifico della piattaforma.

Con solo avere uno sguardo alla mia cstdlib e stdlib.h qui al mio posto ho notato che c'è un interruttore con il quale cstdlib decide se include stdlib.h o semplicemente dichiara abort, atext e exit nel std namespace.

Ovviamente si inserisce il ramo stdlib.h. Guardando oltre in questo file ho notato la macro __BEGIN_NAMESPACE_STD e successivamente __END_NAMESPACE_STD. Forse potresti usare questo, ma è (come suggerisce il nome) alcune macro interne all'implementazione e non dovrebbe essere impostato direttamente da te. Tuttavia, dovrebbe essere lì per qualche motivo, quindi potresti avere fortuna nel cercarlo.

Dopo qualche altra ricerca è risultato che random è una delle varie funzioni (e dichiarazioni) che non sono racchiuse in __BEGIN_NAMESPACE_STD. Pertanto, questa non è una soluzione al problema. (Ho trovato un'altra macro _GLIBCPP_USE_NAMESPACES che sembra essere utilizzata internamente pure a #define __BEGIN_NAMESPACE_STD namespace std {).

Quindi per riassumere: questo non è un percorso praticabile e si dovrebbe utilizzare uno dei metodi descritti.

+0

Mentre la macro stessa è interna, forse c'è qualche switch del compilatore "pubblico" o un'altra macro che può accenderlo? – CygnusX1

+0

Anche questo è il mio pensiero, ma ho non ne ho ancora trovato uno (ho iniziato a cercare quando ho scritto la mia risposta). Inoltre non posso garantire che tutto sia ben confezionato in questo, ma a prima vista sembrava promettente. – Nobody

Problemi correlati