質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.63%

C++で_wprintfに記述したCString型の文字の書式指定子が誤っている

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 181

T.Adams

score 18

分からないこと

_tprintfを使用し書式指定子に、wchar_tの文字列とCString型を混合した文字を出力したいと考えていますが、警告が出ています。CString型の文字列を書式指定子にいれる際、%sでは不適切であるという内容であると思いますが、具体的にどのように対処すべにかわかりません。教えていただけないでしょうか。

ソース

_tprintf(L"%s%s%s", L"データ'" , strDevName , L"'は既に存在します。\n");

警告内容

警告    C4477    'wprintf' : 書式文字列 '%s' には、型 'wchar_t *' の引数が必要ですが、可変個引数 2 は型 'CString' です
警告    C4840    可変個引数関数の引数としての、クラス
'ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>' の移植性のない使用法

環境情報

OS: Windows Server 2016
IDE: Visual Studio 2017
ビルド方法:Unicodeビルド Release|Win32

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+3

strDevNameCStringW(=CStringのUNICODE版)だとして、

_wprintf(L"%s%s%s", L"データ'" , (LPCWSTR)strDevName , L"'は既に存在します。\n");
//または _wprintf(L"%s%s%s", L"データ'" , (const wchar_t*)strDevName , L"'は既に存在します。\n");


としてください。


追記しました:

※takabosoftさんが既にフォローの回答をしてくださっていますが、途中まで書いていたので追記として放流させていただきます。

CString型のstrDevNameをLPCWSTRにキャストすることで、情報が欠落するなどの問題などはないのですか?

この場合においては問題ありません。CStringはATL/MFCで提供されるC++のクラスですが、(LPCWSTR)へキャストする場合のキャスト演算子のオーバーロードがされていて、(LPCWSTR)でキャストすることで、内部で保持している文字列データへのポインターを返すようになっています。以下は、かなり昔の、Visual C++ 6.0 だった頃のCStringクラスの宣言部分抜粋です。※最近のVisual Studioに同梱のCStringクラスはC++のテンプレートで実装されていて、理解するのはもしかしたらひと苦労かもしれません。

// VC98\MFC\INCLUDE\AFX.INL, AFX.H
class CString {
protected:
    LPTSTR m_pchData;   // pointer to ref counted string data

public:
    operator LPCTSTR() const;

    CString::operator LPCTSTR() const
        { return m_pchData; }
...
}


LPCTSTRはANSI(マルチバイト)文字ビルドではLPCSTRに、UNICODE(ワイド)文字ビルドではLPCWSTRに等価となります。

キャストはプログラム熟練者でないと使うなと指摘を受けたことがありまして、このケースはキャストしても情報欠落がないことを説明

既に説明されていますが、今回の場合においては情報欠落はありません。キャストした時のコンパイラからの警告と言うのは、あくまでコンパイラからの「型が違いますよ。プログラマーさん、意識は合っていますか?大丈夫ですか?」と言う警告メッセージです。コードを書いたプログラマー自身が何をやっているのか充分理解しているのであれば問題はありません。キャストをすることでコンパイラからの警告を消すことができ、これは、例えば「コンパイラさん、私は32ビットの型の変数を16ビットの型にキャストしますけど、上位16ビットは使っていないから、問題ないのです。」と言うプログラマーからコンパイラへのコードを介した意思表示です。コンパイル時の警告を消すためにキャストをするのではなく、正しい意識でキャストを伴うコードを書けば、自然とコンパイル時の警告が無くなる、と言う訳です。

※takabosoftさんが提示してくださったマイクロソフトのリンクもぜひ、併せて読んでください。(「C スタイルの文字列に関連する CString の操作方法」)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/15 09:14 編集

    お役に立ててよかったです。なお、_tprintfですとマルチバイト文字ビルドにするとprintfに変換されるので動作しません。そんな場合は_T()マクロで包んで、
    _tprintf(_T("%s%s%s"), _T("データ'"), (LPCTSTR)strDevName, _T("'は既に存在します。\n")); とすれば、UNICODE/マルチバイト文字ビルドのどちらでも動作します。

    キャンセル

  • 2020/02/15 10:49

    追加コメントありがとうございます。
    マルチバイト文字でビルドした際の方法までΣ(゚Д゚)
    今回の要件では、Unicode文字でビルドで問題ないですが、万一マルチバイト文字でビルドした際も問題なく動くようにするためにも、上記の方法参考にさせていただきます。

    キャンセル

  • 2020/02/15 10:56

    _T()マクロで包むマルチバイト/UNICODEの共用コードはちょっと冗長ですけどね。Windows自体は通常、UNICODE(ワイド文字 UTF-16)をネイティブ文字として動作するので、UNICODE前提で書いた方が
    すっきりするし、マルチバイト(MBCSやUTF-8)文字をあえて意識しなければいけない部分では書き分けが必要になるので、それがかえって良い場合もあります。

    キャンセル

+2

_wprintf(L"%s%s%s", L"データ'" , &strDevName[0] , L"'は既に存在します。\n");

でイケそな気がする。試してみて。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/15 03:47

    あー!確かにそれでもいけます!ありがとうございます!

    キャンセル

+1

dodox86さんと内容はほとんど同じですが、

可変個引数関数での CString オブジェクトの使用
https://docs.microsoft.com/ja-jp/cpp/atl-mfc-shared/cstring-operations-relating-to-c-style-strings?view=vs-2019#_core_using_cstring_objects_with_variable_argument_functions

という感じで公式ページに載っているのでやり方的にはOKです(昔はキャスト要らなかったんですけどね)。

このケースはキャストしても情報欠落がないことを説明することはできるのでしょうか?

情報欠落の定義にもよりますが、
以下のように内部で持っている配列の先頭ポインタがそのまま取得されるだけですので(ステップインしてみればわかります)、

    operator PCXSTR() const throw()
    {
        return( m_pszData );
    }

文字列としての情報が欠落することはありません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/15 04:00

    takabosoft様が記載してくださったリンク先、読ませて頂きました。

    一部の C 関数は、可変個の引数を受け取ります。 主な例として printf_s があります。 この種類の関数の宣言方法では、コンパイラは引数の型がわからず、それぞれの引数で実行する変換操作を決定できません。 そのため、可変個の引数を受け取る関数に CString オブジェクトを渡す場合は、明示的な型キャストを使用することが重要です。

    はっきりと明記されていました。自力でたどり着くことができず、お手数おかけしましたが、公式に明記されていること、キャストも意味を理解していれば、情報欠落なくコンパイラと対話できるということが感じられました。ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.63%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる