【问题标题】:Pass CString to fprintf将 CString 传递给 fprintf
【发布时间】:2014-03-09 02:48:21
【问题描述】:

我在一个大型代码库上运行了 Visual Studio 中的代码分析器,我收到了大约十亿个这样的错误:

warning C6284: Object passed as parameter '3' when string is required in call to 'fprintf'

根据http://msdn.microsoft.com/en-us/library/ta308ywy.aspx“这个缺陷可能会产生不正确的输出或崩溃。”然而,我的同事表示,我们可以忽略所有这些错误而不会出现任何问题。所以我的一个问题是,我们是否需要对此采取任何措施,或者我们可以保持原样吗?

如果需要解决这些错误,最好的解决方法是什么?

这样可以吗:

static_cast<const char*>(someCString)

对此有更好或更正确的方法吗?

以下行会生成此警告:

CString str;
fprintf(pFile, "text %s", str);

【问题讨论】:

  • 向我们展示一个发出此警告的调用站点,其中包含所涉及变量的完整声明。
  • 你查看过成员方法GetBuffer(int minBufferLength )吗?它返回一个空终止的LPSTR,我相信它与char* 基本相同,但是它不是const。在这里阅读更多:msdn.microsoft.com/en-us/library/aa314880(v=vs.60).aspx
  • MS 支持与否,这是一种糟糕的做法,我希望你的同事宣传它。我还没有看到 MS 特别 说这样做很好,而且实际上他们的文档特别说要转换为 LPCTSTR 以触发转换运算符。他们的实施“支持”它;为他们求婚。无论他们是否愿意承认,语言标准都胜过他们。如果有标准的小节表明这是合规的,我还没有看到它。
  • 您如何看待@xMRi 建议的GetString() method

标签: c++ mfc portability cstring printf


【解决方案1】:

我假设您将 Microsoft“CString”对象传递给 printf()-family 函数,其中相应的格式说明符为 %s。如果我是对的,那么您的答案就在这里:How can CString be passed to format string %s?(简而言之,您的代码是可以的)。

似乎最初的实现细节允许将 CString 直接传递给 printf(),后来它成为合同的一部分。因此,只要您的程序正确,您就可以很好地进行操作,但是如果您想避免静态分析警告,您可能确实需要将 static_cast 用于 char 指针。我不确定这是否值得……也许还有其他方法可以让这些工具很好地结合在一起,因为它们都来自 Microsoft。

【讨论】:

    【解决方案2】:

    按照 C6284 中的 MSDN 建议,您可以放弃警告。使用 C++ 强制转换将是最易于维护的选项。您上面的示例将更改为

    fprintf(pFile, "text %s", static_cast<const TCHAR*>(str));
    

    或者,只是相同的另一种拼写,to

    fprintf(pFile, "text %s", static_cast<LPCTSTR>(str));
    

    最令人信服的选项100% 无演员表,参见编辑部分)是

    fprintf(pFile, "text %s", str.GetString());
    

    当然,遵循任何这些更改模式都是移植的第一步,如果没有任何迹象表明需要它,这可能是有害的(不仅你的团队氛围)。


    编辑:(根据 xMRi 的评论)

    1) 我添加了const,因为该参数对于 fprintf 是只读的

    2) 无强制转换解决方案CSimpleStringT::GetString 的注释:CSimpleStringT 类模板用于定义CStringT,该模板再次用于对原始问题中使用的类CString 进行类型定义

    3) 重新设计答案以消除噪音。

    4) 减少了关于铸造选项的介绍

    【讨论】:

    • 为什么我应该转换为 TCHAR* 而不是使用 GetBuffer()?
    • 总而言之,如果我们正在考虑移植系统,我们需要对错误进行一些处理。但是,如果我只是想摆脱警告,您可以将其转换为 TCHAR*?
    • @k4rlsson (1) 据我了解,GetBuffer() 分配的内存必须通过调用ReleaseBuffer() 方法释放这也可能与性能相关。 (2) 如果演员表使分析工具的警告消失(我无法检查),我会使用它。这也是一个很好的机会来检查所有十亿警告是否真的相同。
    • 但不允许将 CString 转换为 TCHAR*。只有使用 GetBuffer 才能节省。只有 GetBuffer 是从 CString 获取 TCHAR* 的一种保存方式。在此处显示的代码中,它也没有任何意义,因为 const TCHAR* 就足够了。如果 CString 仅由一个实例使用,GetBuffer 也不会分配任何内容。 Ig 使用了不止一次,它使用 Copy on Write 并复制内容。还有 CString::GetString 可以满足您的所有需求。
    • 这只是一个基本模板。 CString 是 CStringT 的 typedef,它派生自 CSimpleStringT。你有没有研究过这个类的定义?
    【解决方案3】:

    从技术上讲,这是可以的,因为 c-string 以这样一种方式存储在 CString 中,您可以按照说明使用它,但依赖于 CString 的实现方式来执行快捷方式并不好。 printf 是一个 C 运行时函数,对 C++ 对象一无所知,但这里依赖于字符串首先存储在 CString 中 - 一个实现细节。

    如果我没记错的话,最初 CString 不能以这种方式使用,必须将 CString 转换为 c-string 才能打印出来,但在以后的版本中,MS 更改了实现以允许将其视为 c-字符串。

    另一个重大问题是 UNICODE,如果有一天你决定用 UNICODE 字符集编译程序,它肯定不会起作用,因为即使你将所有字符串格式化程序都更改为 %ld,嵌入的 0 有时也会阻止字符串被打印。

    实际的问题是你为什么使用 printf 而不是 C++ 来打印/写入文件?

    【讨论】:

    • 其中一些代码可以追溯到大约 25 年前,这里不能选择替换 printf。
    • 我知道这种感觉 :o) vår kod är från -83
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 2019-05-13
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    相关资源
    最近更新 更多