"fpermissive"标志是什么作用?

154

我想知道g++编译器中的-fpermissive标志是什么意思?我得到了以下错误:

error: taking address of temporary [-fpermissive]

使用-fpermissive标志可以解决这个问题。

编辑: 我刚刚找到了导致临时地址错误的原因!我现在将修复该部分。

7个回答

173

文档中得知:

-fpermissive
将一些关于不符合规范的代码的诊断信息从错误降级为警告。因此,使用-fpermissive将允许一些不符合规范的代码编译。

总的来说:除非你知道自己在做什么,否则不要使用


35
我希望你能够提供比“不要在不了解操作方法时使用”更详细的说明,而且不需要自己去搜索。我需要知道哪些不符合规范的代码会被降级。 - johannes_lalala
不符合规范的代码不会被降级,但诊断将从错误变为警告。问题开启者给出了一个例子。如果你不知道边缘情况可能是什么,就不应该考虑使用它。 - cli_hlt
12
抱歉,朋友,不冒犯,但是像“如果你不知道后果就不要做某事”的建议很平凡,适用于任何问题,没有回答任何问题。 - johannes_lalala
10
抱歉,仅引用手册而没有任何解释是没有帮助的。特别是在手册非常简略的情况下。 - johannes_lalala
@johannes_lalala 我认为一个好的经验法则是,如果(A) 你认为你“知道自己在做什么”,(B) 行为已定义,(C)你在测试套件下运行它,并且(D)没有发生任何不良反应,则你可能知道你在做什么。 - Sapphire_Brick
这确实一点也不有用。任何人都可以查阅一篇文章。很多旗标会将错误变成警告,或者反之亦然。它们都一样吗?有什么区别?然后只是简单地加上“除非你知道你在做什么,否则不要使用它”,也一点也不有用。为什么他们不应该使用呢?也许如果提供更多的信息,人们就会明白为什么他们不应该使用。现在就像是父母告诉你不要做某事,却不告诉你为什么一样。这样并不能教会任何东西。 - undefined

74
-fpermissive 标志 可以使编译器将一些实际上是错误的东西(但一些编译器允许)报告为警告,从而允许代码编译,即使不符合语言规则。你真的应该修复潜在的问题。发布一个最小的、可编译的代码样本来演示问题。

-fpermissive
将一些有关非符合代码的诊断从错误降级为警告。因此,使用 -fpermissive 将允许一些不符合规范的代码编译。


23

当你写了一些不符合语言标准的代码(因此无法被良好定义,这就足以不要这样做),但如果直接输入编译引擎会映射到某种可执行文件时,-fpermissive将继续执行而不是停止并显示错误消息。在某些情况下,程序可能会像你最初预期的那样正常运行,但除非你有一些非常特殊的原因不能使用其他解决方案,否则你绝对不应该依赖它。


4
即使不符合语言标准,某些东西仍然可以被很好地定义。实际上,几乎每个编译器都具有良好定义的扩展功能。不过,并不是所有宽容性的情况下都是如此。 - MikeMB

17

如果你想要一个关于这个的真实案例,可以尝试使用一个“现代”的gcc版本(例如4.9.3)编译一个非常老的X Windows版本,比如说2004年左右的XFree86或XOrg。

你会注意到编译时的CFLAGS指定了“-ansi”和“-pedantic”。理论上,这意味着“即使有任何稍微违反语言规范的东西都会出问题”。实际上,gcc 3.x系列并没有很好地捕捉到这种类型的问题,因此除非你将CFLAGS和BOOTSTRAPCFLAGS设置为“-fpermissive”,否则使用4.9.3编译将会导致失败。

使用该标志,大多数C文件实际上都可以构建,这样你就可以继续处理词法分析器将生成的版本相关崩溃了。=]


3

有一个常见情况是只需设置 -fpermissive 而不必过分担心: 经过充分测试和工作正常的第三方库,在没有 -fpermissive 的较新编译器版本下无法编译。这些库存在,并且很可能不是应用程序开发者需要解决的问题,也不在开发者的进度预算内。

在这种情况下,设置 -fpermissive 并继续前进。


2
上次我遇到这种情况时,库是偶然工作的,实际上正在访问未初始化的内存,后来发现它在 Mac 上崩溃了。 - Joshua

1
一般来说,它“将一些有关非标准代码的诊断从错误降级为警告”。不幸的是,我没有看到允许的具体事项清单。我发表答案的主要原因是建议您尽可能避免使用它。相反,查看每个错误并查看是否可以修复。OP找到并修复了导致其错误的原因。 (“获取临时地址”可能是调用返回std :: string对象的函数,并将某些内容分配给瞬态对象的c_ptr()值。)我刚刚回顾了一个涉及升级gcc版本的项目,开发人员添加了 -fpermissive ,因为突然出现了一堆编译错误。我注意到其中一个测试是:
    if (myPointer == '\0')

我指出应该这样做:

    if (myPointer[0] == '\0')

开发人员检查后发现,每一个标记的东西都是一个真正的错误 - 其中一些已经存在了超过20年。


0

正如 @cli_hlt 所提到的

底线:除非你知道自己在做什么,否则不要使用它!

它可能会做出可怕的事情,例如编译器有时会取消 std::map 变量的常量性:

#include <map>
#include <vector>
#include <iostream>
#include <string>
struct B{
    std::map<std::string, int> m_map;
    std::vector<int> m_vector;
    B(){
        m_map["a"] = 1;
        m_map["b"] = 2;
        m_map["c"] = 3;
        m_vector.emplace_back(1);
        m_vector.emplace_back(2);
        m_vector.emplace_back(3);
    }
    const std::map<std::string, int>& getMap() const {
        return m_map;
    }
    const int& getMapValue(const std::string& key) const {
        return m_map.at(key);
    }
    const std::vector<int>& getVector() const {
        return m_vector;
    }
    const int& getVectorValue(const int& i) const {
        return m_vector[i];
    }
};

int main(){
    B b;
    auto& my_map = b.getMap(); // we get const ref here
    my_map["a"] = 10; // here we can modify it
    std::cout << "my_map[a]=" << my_map.at("a") << std::endl;

    auto& my_map2 = b.getMap();  // here we return already modified variable
    std::cout << "my_map2[a]=" << my_map2.at("a") << std::endl;

    auto& my_value = b.getMapValue("b");
    // my_value = 20; // compiler error
    // std::cout << "my_map[b]=" << my_value << std::endl;

    auto& my_vector = b.getVector();
    // my_vector[0] = 10; // compiler error
    // std::cout << "my_vector[0]=" << my_vector[0] << std::endl;

    const int a = 10;
    auto& a1 = a;
    // a1 = 100; // compiler error
}

正如您所看到的,您无法保证地图的常数性,但是可以保留向量或值的常数性。 附言:我在以下编译器GCC 12.1、9.1、8.1、7.1、6.1中进行了测试。 然而,clang没有-fpermissive标志(有此),它会捕获错误。


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