C ++ std :: string替代strcpy?

时间:2011-10-21 16:06:17

标签: c++ stdstring 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是一种窗口结构,lfFaceName定义为TCHAR lfFaceName[LF_FACESIZE]

我想知道的是,我可以做以下事情(如果不是,为什么不这样做):

void MyControl::SetFontFace(const std::string& faceName)
...
  lf.lfFaceName = faceName.c_str();
...

或者如果完全有不同的选择,请告诉我。

5 个答案:

答案 0 :(得分:8)

您收到安全警告的原因是,您的faceName参数可能指向更长的字符串,而不是LF_FACESIZE个字符,然后{{1}会盲目地覆盖strcpy结构中lfFaceName之后的任何内容。你确实有一个错误。

您应通过将LOGFONT更改为strcpy来盲目修复错误,因为:

  1. strcpy_s函数是不可移植的Microsoft发明几乎所有这些函数都复制了 可移植的其他C库函数的功能。永远不要使用它们,即使是在不打算携带的程序中(如图所示)。
  2. 盲目的改变往往不会真正解决这类错误。例如,*_sstrcpystrncpystrlcpy)的“安全”变体只会截断字符串,如果它太长,在这种情况下会让你尝试加载错误的字体。更糟糕的是,strcpy_s在执行此操作时省略了NUL终止符,因此如果您使用该崩溃,则可能只是在strncpy内移动崩溃。 正确的修复是预先检查长度,如果时间过长则无法完成整个操作。此时CreateFontIndirect变得安全(因为你知道它不会太长),虽然我更喜欢strcpy,因为它让我对这段代码的未来读者显而易见。
  3. memcpyTCHAR不是一回事;将C样式char字符串或C ++ const char *复制到std::string数组中而没有正确的编码转换可能会产生完全无意义的错误。 (根据我的经验,使用TCHAR总是一个错误,最大的问题是像这样的代码似乎在ASCII构建中正常工作,并且仍然会编译 UNICODE模式,但在运行时会发生灾难性故障。)
  4. 您当然可以使用TCHAR 帮助解决此问题,但它不会让您无需检查长度并手动复制字符串。我可能会这样做。请注意,我使用std::stringLOGFONTW以及CreateFontIndirectW中UTF-8的显式转换。另请注意,其中的大块是MSDN中的货物,并且没有一个已经过测试。遗憾。

    std::string

答案 1 :(得分:3)

lf.lfFaceName = faceName.c_str();

不,你不应该这样做,因为你正在为std :: string中保存的数据制作poitner的本地副本。如果c ++字符串发生更改或被删除,则指针不再有效,如果lFaceName决定更改数据,这几乎肯定会破坏std :: string。

由于你需要复制一个c字符串,你需要一个'c'函数,然后strcpy_s(或它的等价物)是安全的替代

答案 2 :(得分:0)

你尝试过吗?鉴于帖子中的信息,分配应该生成编译器错误,因为你试图分配一个指向数组的指针,这在C(++)中不起作用。

#include <cstdio>
#include <string>
using namespace std;

struct LOGFONT {
 char lfFaceName[3];
};


int main() {
        struct LOGFONT f;
        string foo="bar";
        f.lfFaceName = foo.c_str();
        return 0;
}

导致

x.c:13: error: incompatible types in assignment of `const char*' to `char[3]'

我建议使用像警告所说的安全strcpy替代方案,因为无论如何你都知道目标空间的大小。

答案 3 :(得分:0)

lf.lfFaceName = faceName.c_str();因两个原因无效(假设您将faceName更改为std:string)

  1. c_str()返回的指针的生命周期是临时的。只要fileName对象没有更改并且处于活动状态,它才有效。
  2. 该行不会编译。 .c_str()返回指向char的指针,lfFaceName是一个字符数组,无法分配给它。你需要做一些事情来填充字符串数组,填写lfFaceName中的字节,指针赋值不会这样做。
  3. 在这里没有任何C ++可以提供帮助,因为lfFaceName是一个C“字符串”。您需要使用C字符串函数,如strcpy或strcpy_s。您可以将代码更改为:

    strcpy_s(lf.lfFaceName, LF_FACESIZE, faceName);
    

答案 4 :(得分:0)

#include <algorithm>
#include <iostream>
#include <string>

enum { LF_FACESIZE = 256 }; // = 3 // test too-long input
struct LOGFONT
{
    char lfFaceName[LF_FACESIZE];
};

int main()
{
    LOGFONT f;
    std::string foo("Sans-Serif");
    std::copy_n(foo.c_str(), foo.size()+1 > LF_FACESIZE ? LF_FACESIZE : foo.size()+1,
                f.lfFaceName);

    std::cout << f.lfFaceName << std::endl;
    return 0;
}