C++ std::string 可以替代 strcpy 吗?
我知道已经有一个类似标题的问题,但我想知道针对这个特定案例的选择。
MSVC 编译器给出有关 strcpy 的警告:
1>c:\something\mycontrol.cpp(65): warning C4996: 'strcpy': This function or
variable may be unsafe. Consider using strcpy_s instead. To disable
deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
这是我的代码:
void MyControl::SetFontFace(const char *faceName)
{
LOGFONT lf;
CFont *currentFont = GetFont();
currentFont->GetLogFont(&lf);
strcpy(lf.lfFaceName, faceName); <--- offending line
font_.DeleteObject();
// Create the font.
font_.CreateFontIndirect(&lf);
// Use the font to paint a control.
SetFont(&font_);
}
注意 font_
是一个实例变量。 LOGFONT
是一个 Windows 结构,其中 lfFaceName
定义为 TCHAR lfFaceName[LF_FACESIZE]
。
我想知道的是我可以做类似以下的事情(如果不是为什么不):
void MyControl::SetFontFace(const std::string& faceName)
...
lf.lfFaceName = faceName.c_str();
...
或者如果有完全不同的替代方案,请告诉我。
I know there is a similarly titled question already on SO but I want to know my options for this specific case.
MSVC compiler gives a warning about strcpy:
1>c:\something\mycontrol.cpp(65): warning C4996: 'strcpy': This function or
variable may be unsafe. Consider using strcpy_s instead. To disable
deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Here's my code:
void MyControl::SetFontFace(const char *faceName)
{
LOGFONT lf;
CFont *currentFont = GetFont();
currentFont->GetLogFont(&lf);
strcpy(lf.lfFaceName, faceName); <--- offending line
font_.DeleteObject();
// Create the font.
font_.CreateFontIndirect(&lf);
// Use the font to paint a control.
SetFont(&font_);
}
Note font_
is an instance variable. LOGFONT
is a windows structure where lfFaceName
is defined as TCHAR lfFaceName[LF_FACESIZE]
.
What I'm wondering is can I do something like the following (and if not why not):
void MyControl::SetFontFace(const std::string& faceName)
...
lf.lfFaceName = faceName.c_str();
...
Or if there is a different alternative altogether then let me know.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您收到安全警告的原因是,您的
faceName
参数可能指向一个比LF_FACESIZE
字符长的字符串,然后 < code>strcpy 会盲目地覆盖LOGFONT
结构中lfFaceName
之后的任何内容。你确实有一个错误。您不应该通过将
strcpy
更改为strcpy_s
来盲目地修复该错误,因为:*_s
函数是不可移植的 Microsoft几乎所有的发明都复制了其他可移植的 C 库函数的功能。永远不应该使用它们,即使是在不打算移植的程序中(正如看起来的那样)。strcpy
的“安全”变体(strncpy
、strlcpy
、strcpy_s
)仅在以下情况下截断字符串:它太长了,在这种情况下会让您尝试加载错误的字体。更糟糕的是,strncpy 在执行此操作时会忽略 NUL 终止符,因此如果您使用了 CreateFontIndirect,您可能会将崩溃移至 CreateFontIndirect 内。 正确的修复方法是预先检查长度,如果太长则整个操作失败。在这一点上,strcpy变得安全(因为你知道它不会太长),尽管我更喜欢memcpy,因为它让未来的代码读者可以清楚地看到我所认为的关于这个。TCHAR
和char
不是同一件事;将 C 样式const char *
字符串或 C++std::string
复制到TCHAR
数组而不进行适当的编码转换可能会产生完全是胡说八道。 (根据我的经验,使用TCHAR
总是一个错误,最大的问题是这样的代码在 ASCII 构建中似乎可以正常工作,并且仍然可以编译 在 UNICODE 模式下,但在运行时会发生灾难性的失败。)您当然可以使用
std::string
来帮助解决这个问题,但它不会帮助您无需检查长度并手动复制字符串。我可能会这样做。请注意,我在std::string
中使用LOGFONTW
和CreateFontIndirectW
以及从 UTF-8 的显式转换。另请注意,其中大部分内容是从 MSDN 中收集而来的,并且没有经过测试。对不起。The reason you're getting the security warning is, your
faceName
argument could point to a string that is longer thanLF_FACESIZE
characters, and thenstrcpy
would blindly overwrite whatever comes afterlfFaceName
in theLOGFONT
structure. You do have a bug.You should not blindly fix the bug by changing
strcpy
tostrcpy_s
, because:*_s
functions are unportable Microsoft inventions almost all of which duplicate the functionality of other C library functions that are portable. They should never be used, even in a program not intended to be portable (as this appears to be).strcpy
(strncpy
,strlcpy
,strcpy_s
) simply truncate the string if it's too long, which in this case would make you try to load the wrong font. Worse,strncpy
omits the NUL terminator when it does that, so you'd probably just move the crash insideCreateFontIndirect
if you used that one. The correct fix is to check the length up front and fail the entire operation if it's too long. At which pointstrcpy
becomes safe (because you know it's not too long), although I prefermemcpy
because it makes it obvious to future readers of the code that I've thought about this.TCHAR
andchar
are not the same thing; copying either a C-styleconst char *
string or a C++std::string
into an array ofTCHAR
without a proper encoding conversion may produce complete nonsense. (UsingTCHAR
is, in my experience, always a mistake, and the biggest problem with it is that code like this will appear to work correctly in an ASCII build, and will still compile in UNICODE mode, but will then fail catastrophically at runtime.)You certainly can use
std::string
to help with this problem, but it won't get you out of needing to check the length and manually copy the string. I'd probably do it like this. Note that I am usingLOGFONTW
andCreateFontIndirectW
and an explicit conversion from UTF-8 in thestd::string
. Note also that chunks of this were cargo-culted out of MSDN and none of it has been tested. Sorry.lf.lfFaceName = faceName.c_str();
不,您不应该这样做,因为您正在将指向器的本地副本复制到 std::string 中保存的数据。如果 c++ 字符串更改或被删除,则指针不再有效,并且如果 lFaceName 决定更改数据,这几乎肯定会破坏 std::string。
由于您需要复制 ac 字符串,因此需要一个 'c' 函数,那么 strcpy_s (或等效的)是安全的替代方案
lf.lfFaceName = faceName.c_str();
No you shouldn't do that because you are making a local copy of the poitner to the data held inside the std::string. If the c++ string changes, or is deleted, the pointer is no longer valid, and if lFaceName decides to change the data this will almost certainly break the std::string.
Since you need to copy a c string, you need a 'c' function, then strcpy_s (or it's equivalent) is the safe alternative
你尝试过吗?鉴于您帖子中的信息,该赋值应该会生成编译器错误,因为您尝试将指针分配给数组,这在 C(++) 中不起作用。
导致
我建议使用安全的 strcpy 替代方案,如警告所述,前提是您无论如何都知道目标空间的大小。
Have you tried? Given the information in your post, the assignment should generate a compiler error because you're trying to assign a pointer to an array, which does not work in C(++).
leads to
I'd recommend using a secure strcpy alternative like the warning says, given that you know the size of the destination space anyway.
lf.lfFaceName = faceName.c_str();
不起作用有两个原因(假设您将faceName 更改为std:string)没有任何 C++ 可以帮助这里,因为 lfFaceName 是一个 C“字符串”。您需要使用 C 字符串函数,例如 strcpy 或 strcpy_s。您可以将代码更改为:
lf.lfFaceName = faceName.c_str();
won't work for two reasons (assuming you change faceName to a std:string)There isn't anything C++ that can help here, since lfFaceName is a C "string". You need to use a C string function, like strcpy or strcpy_s. You can change your code to: