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

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

新規登録して質問してみよう
ただいま回答率
85.37%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

8933閲覧

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

T.Adams

総合スコア40

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/02/14 05:17

編集2020/02/14 18:50

分からないこと

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

ソース

C++

1_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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

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

C++

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

としてください。


追記しました:

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

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

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

C++

1// VC98\MFC\INCLUDE\AFX.INL, AFX.H 2class CString { 3protected: 4 LPTSTR m_pchData; // pointer to ref counted string data 5 6public: 7 operator LPCTSTR() const; 8 9 CString::operator LPCTSTR() const 10 { return m_pchData; } 11... 12}

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

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

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

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

投稿2020/02/14 05:21

編集2020/02/14 09:00
dodox86

総合スコア9254

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T.Adams

2020/02/14 07:12

dodox86様 迅速なご返答ありがとうございます。上記方法で警告なくビルドすることができました。 1点ご確認したいのですが、CString型のstrDevNameをLPCWSTRにキャストすることで、情報が欠落するなどの問題などはないのですか?以前、キャストはプログラム熟練者でないと使うなと指摘を受けたことがありまして、このケースはキャストしても情報欠落がないことを説明することはできるのでしょうか?
dodox86

2020/02/14 09:01

追記しましたのでtakabosoftさんの回答も併せ、ご覧ください。
dodox86

2020/02/14 09:06

この際大きな問題ではないのですけど、_wrpintfってありましたっけ。_wprintf_lとか、_tprintfならありますけど。
T.Adams

2020/02/14 18:46

_tprintfです。訂正いたします。ご指摘ありがとうございます。
T.Adams

2020/02/14 18:48

Unicodeでビルドしています。情報として追記しておきます。
T.Adams

2020/02/14 19:05

非常に丁寧な回答ありがとうございました。 takabosoft様のリンク先も併せて読ませて頂きました。以下の文面の意味を理解できました。 >(LPCWSTR)でキャストすることで、内部で保持している文字列データへのポインターを返すようになっています。 ビルドした際、いつも警告が出ないかビクビクしており、出た警告に対する対処が正しいかどうか不安になることが多いですが(もちろん対処方法はチームメンバーとのレビュー等で品質の確保はしております)、dodox86様が記載してくださった「プログラマーからコンパイラへのコードを介した意思表示です。」という言葉に共感いたしました。 非常に勉強になりましたし、私もまだまだ未熟ですが更に精進できるよう、プログラムを続けていこうと思いました。
dodox86

2020/02/15 00:15 編集

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

2020/02/15 01:49

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

2020/02/15 01:56

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

0

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

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

投稿2020/02/14 10:54

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T.Adams

2020/02/14 18:47

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

0

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です(昔はキャスト要らなかったんですけどね)。

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

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

cpp

1 operator PCXSTR() const throw() 2 { 3 return( m_pszData ); 4 }

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

投稿2020/02/14 08:28

編集2020/02/14 08:28
takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T.Adams

2020/02/14 19:00

takabosoft様が記載してくださったリンク先、読ませて頂きました。 一部の C 関数は、可変個の引数を受け取ります。 主な例として printf_s があります。 この種類の関数の宣言方法では、コンパイラは引数の型がわからず、それぞれの引数で実行する変換操作を決定できません。 そのため、可変個の引数を受け取る関数に CString オブジェクトを渡す場合は、明示的な型キャストを使用することが重要です。 はっきりと明記されていました。自力でたどり着くことができず、お手数おかけしましたが、公式に明記されていること、キャストも意味を理解していれば、情報欠落なくコンパイラと対話できるということが感じられました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問