C/C++ 是否有跨平台的使用相对路径的方式?

4
我正在使用SDL编写一个小游戏,文件的结构如下所示:
"src/game/"包含.h和.cpp源文件。
"data/"包含游戏文件,例如地图、图块集、精灵等等...
例如要加载一个精灵,我将使用以下代码。
spriteLib.loadSprite("data/sprites/sprite-ghost.bmp");

为了将此字符串转换为绝对路径,我在函数的前4行中有以下代码:

SSprite CSpriteLib::loadSprite(std::string file)
{
    //Converting the file path
    char converted[128];
    realpath(file.c_str(),converted);
    file = converted;

但这种方法只能在Linux下编译,如果有其他方法,请告知,我将不胜感激。

4个回答

5
Boost是你的好朋友。这里有一个链接到Boost Filesystem教程的链接

哇,回答得好快啊,我得稍后测试一下,因为这里已经是凌晨3点半了。 - bardes

3
一些要点:
char converted[128];
realpath(file.c_str(),converted);
  1. 首先,一些操作系统(如Solaris)上的realpath可能仍然返回相对路径。
  2. 您的代码存在缓冲区溢出问题,最好使用canonicalize_file_namechar *m=realpath(file.c_str(),0); ... free(m);-不过这只适用于Linux。请参阅man realpath以了解如何更或多或少地正确使用它。

此外,realpath如何帮助您打开数据?如果

fopen(converted,"r")

适用于您的情况。
fopen(file.c_str(),"r")

也可以工作。它提供了帮助删除所有符号链接等内容的功能。

如果您需要类似于realpath的功能,则可以在Windows下使用GetFullPathName,但是它的行为仍然不同。


我不知道fopen会使用相对路径,谢谢你的提示,但是IMG_Load()和SDL_LoadBMP()只能使用绝对路径,怎么办? - bardes

1

我刚写了一个小类:

#include <string>
#include <vector>
#include <iostream>

class CFilePath
{
        typedef std::vector<std::string> TPath;
    public:
        enum EPlatform
        {  
            Windows,
            Unix
        };
        CFilePath(EPlatform p_platform) : m_platform(p_platform) {}
        CFilePath& operator/(const char* p_path)
        {  
            m_path.push_back(p_path);
            return *this;
        }

        std::string GetPath()
        {  
            std::string ret;
            if (m_path.empty())
                return ret;
            for (unsigned i = 0; i < m_path.size();)
            {
                ret+=m_path[i];
                i++;
                if (i < m_path.size())
                {  
                    switch (m_platform)
                    {  
                        case Windows:
                            ret+="\\";
                            break;
                        case Unix:
                            ret+="/";
                            break;
                    }
                }
            }
            return ret;
        }
        operator const char*()
        {
            return GetPath().c_str();
        }
        EPlatform m_platform;

    private:
        std::vector<std::string> m_path;
};

int main(int argc, char* argv[])
{
    CFilePath::EPlatform platform = CFilePath::Windows; // variable
    CFilePath path(platform);
    path/"data"/"sprites"/"sprite-ghost.bmp";
    std::cout << path << std::endl;
    path.m_platform = CFilePath::Unix;
    std::cout << path << std::endl;

    return 0;
}

将会打印:

data\sprites\sprite-ghost.bmp
data/sprites/sprite-ghost.bmp

0
我的建议是:首先,您的主程序应该接受一个本地文件名作为参数,表示程序数据所在的位置,例如

C:\program files\mycompany\mygame

这将责任转移给其他程序(例如bash脚本或驱动程序等)来决定使用哪些数据。

其次,使用Unix格式定义目录空间中的数据子部分,以便您程序中的所有文件名文字都具有此格式。没有任何条件,始终使用Unix。例如:

spriteLib.loadSprite("data/sprites/sprite-ghost.bmp");

现在编写一个函数,将传入的目录名称(以本地格式)与转换为本地格式的unix文件名组合起来,以获得适合访问的文件名。您已经尝试过这样做,但正在使用依赖于操作系统的函数。不要这样做。自己编写它。您想得到这个:
C:\program files\mycompany\mygame\data\sprites\sprite-ghost.bmp

@Industrial-antidepressant(之前是@nice blonde stupid girl)的方法也很不错,但需要更多的工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接