c++ c++17 std-filesystem

Error nativo del separador de ruta en C++ 17 std:: filesystem:: path?



c++17 std-filesystem (3)

A grandes rasgos, un error en un compilador ocurre cuando exhibe un comportamiento que está prohibido por el estándar (ya sea explícita o implícitamente), o un comportamiento que difiere de la documentación de dicho compilador.

El estándar no impone restricciones en el formato de las cadenas de ruta de acceso nativas, excepto que el sistema operativo subyacente debe aceptar el formato (cita a continuación). ¿Cómo podría imponer tales restricciones? El lenguaje no tiene ninguna opinión sobre la forma en que el sistema operativo host maneja las rutas, y para hacerlo con confianza tendría que saber cada objetivo en el que se puede compilar, lo que claramente no es factible.

[fs.class.path]

5 Una ruta de acceso es una cadena de caracteres que representa el nombre de una ruta. Los nombres de ruta se formatean de acuerdo con la gramática genérica del formato de ruta de acceso ([fs.path.generic]) o de acuerdo con un formato de ruta de acceso nativo dependiente del sistema operativo aceptado por el sistema operativo host .

(Énfasis mío)

La documentación de MSVC implica que la barra diagonal es perfectamente aceptable como separador:

Común a ambos sistemas es la estructura impuesta en una ruta de acceso una vez que supera el nombre de la raíz. Para la ruta c: /abc/xyz/def.ext:

  • El nombre de la raíz es c:
  • El directorio raíz es / .
  • La ruta raíz es c:/ .
  • La ruta relativa es abc/xyz/def.ext .
  • La ruta principal es c:/abc/xyz .
  • El nombre del archivo es def.ext .
  • El tallo es def .
  • La extensión es .ext .

Menciona un separador preferido, pero esto realmente solo implica el comportamiento de std::make_preferred , y no de la salida de ruta predeterminada:

Una diferencia menor es el separador preferido , entre la secuencia de directorios en una ruta de acceso. Ambos sistemas operativos le permiten escribir una barra inclinada / , pero en algunos contextos, Windows prefiere una barra diagonal inversa / .

La pregunta de si esto es un error, entonces, es fácil: dado que el estándar no impone restricciones en el comportamiento, y la documentación del compilador no implica la necesidad de una barra inclinada hacia atrás, no puede haber ningún error.

Lo que queda es la cuestión de si se trata de un problema de calidad de implementación . Después de todo, se espera que los implementadores de compiladores y bibliotecas conozcan todas las peculiaridades de su objetivo e implementen las funciones en consecuencia.

Depende del debate qué barra ( ''/' o ''/'' ) debe usar en Windows, o si realmente importa, por lo que no puede haber una respuesta autorizada. Cualquier respuesta que abogue por uno u otro debe ser muy cuidadosa para no basarse demasiado en la opinión. Además, la mera existencia de path::make_preferred indica que la ruta nativa no es necesariamente la preferida. Considere el principio de cero sobrecarga : hacer que el camino sea siempre el preferido incurriría en un gasto general para las personas que no necesitan ser tan pedantes cuando manejan caminos.

Finalmente, el std::experimental nombres std::experimental es lo que dice en el recuadro: no debe esperar que la biblioteca estandarizada final se comporte como su versión experimental, o incluso esperar que exista una biblioteca estandarizada final. Así es como es, cuando se trata de cosas experimentales.

Encontré un problema al actualizar de #include <experimental/filesystem> a #include <filesystem> . Parece que el método std::filesystem::path::wstring no está devolviendo la misma cadena que en experimental::filesystem . Escribí el siguiente programa de prueba pequeño con el resultado de salida incluido.

#include <iostream> #include <filesystem> #include <experimental/filesystem> namespace fs = std::filesystem; namespace ex = std::experimental::filesystem; using namespace std; int main() { fs::path p1{ L"C://temp/foo" }; wcout << "std::filesystem Native: " << p1.wstring() << " Generic: " << p1.generic_wstring() << endl; ex::path p2{ L"C://temp/foo" }; wcout << "std::experimental::filesystem Native: " << p2.wstring() << " Generic: " << p2.generic_wstring() << endl; } /* Output: std::filesystem Native: C:/temp/foo Generic: C:/temp/foo std::experimental::filesystem Native: C:/temp/foo Generic: C:/temp/foo */

De acuerdo a https://en.cppreference.com/w/cpp/filesystem/path/string :

Valor de retorno

La ruta de acceso interna en formato de ruta de acceso nativo, convertida al tipo de cadena especificado.

El programa se ejecutó en Windows 10 y se compiló con Visual Studio 2017 versión 15.8.0. Espero que la ruta de acceso nativa sea C:/temp/foo .

Pregunta: ¿Es esto un error en std::filesystem::path ?


Cualquiera de los dos podría considerarse "nativo" en la plataforma, por lo que cualquiera de esas opciones es igualmente válida. La API del sistema de archivos no garantiza que la versión "nativa" sea idéntica a la cadena que le dio, independientemente de la plataforma. Tampoco existe una garantía de que la cadena "nativa" solo usará el separador de directorio nativo si el carácter "/" genérico es equivalente a él.


No, no es un error!

https://en.cppreference.com/w/cpp/filesystem/path/string y c_str()/native() devuelven la ruta interna en formato nativo de ruta.

Lo que significa nativo

MS afirma , utiliza ISO / IEC TS 18822: 2015 . El borrador final define el formato de ruta de acceso nativo en §4.11 de la siguiente manera:

El formato de la ruta dependiente del sistema operativo aceptado por el sistema operativo del host .

En Windows, native() devuelve la ruta como std::wstring() .

Cómo forzar el uso de barras diagonales inversas como separador de directorios en Windows

El estándar define el término preferred-separator (ver también §8.1 (gramática del formato de ruta de acceso) ):

Un carácter separador de directorio dependiente del sistema operativo.

Una ruta se puede convertir (en su lugar) en el separador preferido con path::make_preferred . En Windows, tiene el operador noexcept .

¿Por qué no debes preocuparte?

La documentación de MS sobre estados de rutas sobre el uso de / vs /

Las funciones de E / S de archivos en la API de Windows convierten "/" a "/" como parte de la conversión del nombre a un nombre de estilo NT, excepto cuando se usa el prefijo "/? /" Como se detalla en las siguientes secciones.

y en la documentación sobre la navegación de archivos C ++ , la barra inclinada (conocida como fallback-separator en los borradores más recientes) incluso se usa directamente después del root-name :

path pathToDisplay(L"C:/FileSystemTest/SubDir3/SubDirLevel2/File2.txt ");

Ejemplo para VS2017 15.8 con -std:C++17 :

#include <filesystem> #include <iostream> namespace fs = std::filesystem; void output(const std::string& type, fs::path& p) { std::cout << type << ":/n" << "- native: " << p.string() << "/n" << "- generic: " << p.generic_string() << "/n" << "- preferred-separator" << p.make_preferred() << "/n"; } int main() { fs::path local_win_path("c:/dir/file.ext"); fs::path unc_path("//your-remote/dir/file.ext"); output("local absolute win path", local_win_path); output("unc path", unc_path); unc_path = "//your-remote/dir/file.ext"; // Overwrite make_preferred applied above. if (fs::is_regular_file(unc_path)) { std::cout << "UNC path containing // was understood by Windows std filesystem"; } }

Salida posible (cuando unc_path es un archivo existente en un control remoto existente):

local absolute win path: - native: c:/dir/file.ext - generic: c:/dir/file.ext - preferred-separator"c://dir//file.ext" unc path: - native: //your-remote/dir/file.ext - generic: //your-remote/dir/file.ext - preferred-separator"////your-remote//dir//file.ext" UNC path containing // was understood by Windows std filesystem

Por lo tanto, las transformaciones de ruta explícitas al separador preferido solo deberían ser necesarias cuando se trabaja con bibliotecas que imponen el uso de ese separador para la interacción de su sistema de archivos.