首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >警告:带有GCC 11.2.1的空目标指针[-Wformat-溢出=]

警告:带有GCC 11.2.1的空目标指针[-Wformat-溢出=]
EN

Stack Overflow用户
提问于 2022-07-17 04:02:12
回答 2查看 176关注 0票数 2

这是我的代码:

代码语言:javascript
运行
复制
#include <iostream>
#include <cstdio>

int main()
{
    char *str = new char[64] ;
    std::sprintf(str, "msg: %s", "hello world") ;

    std::cout << str << std::endl ;
    delete [] str ;

    return 0 ;
}

使用GCC 11.2.1,使用以下命令:

代码语言:javascript
运行
复制
g++ -O -fsanitize=undefined -Wformat-overflow test.cpp

我得到:

代码语言:javascript
运行
复制
test.cpp:7:17: warning: null destination pointer [-Wformat-overflow=]
    7 |     std::sprintf(str, "msg: %s", "hello world") ;
      |     ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我不明白发出警告的原因。我做错什么了吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-07-17 04:48:51

这似乎是来自g++编译器的错误/假阳性警告。该消息试图警告您,如果指针为null (或指向大小不足的缓冲区),则使用指针变量作为sprintf函数的目标可能会失败。

抑制此警告是“微不足道的”:只需在调用str之前添加一个str不为空的检查即可。

代码语言:javascript
运行
复制
if (str) std::sprintf(str, "msg: %s", "hello world");

但是,您的代码是好的,而且这种检查是完全多余的,因为标准运算符new [] (正如您使用的那样),不能返回空指针。您使用的是new的“版本(2)”,如此cppreference首选项页面所述。注:同一页:

将值1-4)非空指针返回到大小至少为size的适当对齐内存。

如果您的new char[64]表达式未能分配足够的内存,那么将抛出一个异常,并且(如您的代码所示)将不会调用sprintf函数。

票数 3
EN

Stack Overflow用户

发布于 2022-07-17 05:33:59

为了补充禤浩焯的答案,尽管你的代码是正确的,GCC发出警告的原因是对delete[]的明确调用。我发现注释掉这一行删除了警告。我认为GCC是在一个简单的上下文中看到delete[]调用的(可能是因为它在析构函数之外),它认为内存在使用时可能被释放。

如果使用gcc命令将代码移动到纯C上下文(使用malloc和free),则警告仍然存在,这意味着它可能检测空闲(使用free()delete[]),并警告您数据可能是在空闲后读写(即使在本例中不是)。GCC没有删除char数组指针的副本可能是一个错误,但我不太确定。上面可能有GCC的窃听器报告,但我找不到。这是我测试的代码。

注: GCC版本: 11.3.0,虽略有增加,但仍坚持GCC-11.我仍然使用与您的示例相同的标志/选项。

代码语言:javascript
运行
复制
#include <stdlib.h>
#include <stdio.h>

int main()
{
    char* str = (char*)malloc(sizeof(char) * 64);

    sprintf(str, "msg: %s", "hello world");
    
    printf("%s\n", str);

    free(str);

    return 0;
}

但是,在具体使用g++时,如果您使用malloc并释放它,它将出于某种原因删除警告。以下是相应的代码:

代码语言:javascript
运行
复制
#include <iostream>
#include <cstdio>

int main()
{
    char* str = (char*)std::malloc(sizeof(char) * 64);

    std::sprintf(str, "msg: %s", "hello world");
    
    std::cout << str << std::endl;

    std::free(str);

    return 0;
}

注意:我使用std::cout来保持与给定代码的一致性,并且如果我使用std::printf,则警告仍然存在。

如果您专门使用C++,则可以使用std::string

代码语言:javascript
运行
复制
#include <iostream>
#include <string>
#include <cstdio>

int main()
{
    std::string str(64, ' ');  ///< allocate a std::string with 64 characters, each initialised to a space (' ').

    std::sprintf(&str[0], "msg: %s", "hello world");  ///< Get the pointer to the first value (C-style) by indexing the string and using the address operator (&)
    
    std::cout << str << std::endl;

    return 0;
}

上面的代码没有手动内存管理,它是由std::string完成的。不过,如果您正在学习C++中的内存功能,我确实理解它。希望这一切都很清楚。

注意:std::string的c_str()方法在这里不适用于std::sprintf,因为它需要一个char*,但是c_str()返回一个const char*

注意:是的,我知道&也可以是引用运算符或位和运算符,但是在这种情况下,它被用来获得C中的地址。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73009176

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档