这是我的代码:
#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,使用以下命令:
g++ -O -fsanitize=undefined -Wformat-overflow test.cpp
我得到:
test.cpp:7:17: warning: null destination pointer [-Wformat-overflow=]
7 | std::sprintf(str, "msg: %s", "hello world") ;
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我不明白发出警告的原因。我做错什么了吗?
发布于 2022-07-16 20:48:51
这似乎是来自g++编译器的错误/假阳性警告。该消息试图警告您,如果指针为null (或指向大小不足的缓冲区),则使用指针变量作为sprintf
函数的目标可能会失败。
抑制此警告是“微不足道的”:只需在调用str
之前添加一个str
不为空的检查即可。
if (str) std::sprintf(str, "msg: %s", "hello world");
但是,您的代码是好的,而且这种检查是完全多余的,因为标准运算符new []
(正如您使用的那样),不能返回空指针。您使用的是new
的“版本(2)”,如此cppreference首选项页面所述。注:同一页:
将值1-4)非空指针返回到大小至少为
size
的适当对齐内存。
如果您的new char[64]
表达式未能分配足够的内存,那么将抛出一个异常,并且(如您的代码所示)将不会调用sprintf
函数。
发布于 2022-07-16 21:33:59
为了补充禤浩焯的答案,尽管你的代码是正确的,GCC发出警告的原因是对delete[]
的明确调用。我发现注释掉这一行删除了警告。我认为GCC是在一个简单的上下文中看到delete[]调用的(可能是因为它在析构函数之外),它认为内存在使用时可能被释放。
如果使用gcc
命令将代码移动到纯C上下文(使用malloc和free),则警告仍然存在,这意味着它可能检测空闲(使用free()
或delete[]
),并警告您数据可能是在空闲后读写(即使在本例中不是)。GCC没有删除char数组指针的副本可能是一个错误,但我不太确定。上面可能有GCC的窃听器报告,但我找不到。这是我测试的代码。
注: GCC版本: 11.3.0,虽略有增加,但仍坚持GCC-11.我仍然使用与您的示例相同的标志/选项。
#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并释放它,它将出于某种原因删除警告。以下是相应的代码:
#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
。
#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中的地址。
https://stackoverflow.com/questions/73009176
复制相似问题