みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C++ strlenに関して

visual studio 2010を使ってC++の勉強を始めました。
これまではJAVAによる開発をやっていました。
strlenの定義を観ようと思い定義へ移動すると
string.hの中に下記のように書かれていました。
--------------------------------------------------------------------

_Check_return_ size_t __cdecl strlen(_In_z_ const char * _Str);

-----------------------------------------------------------------------
初歩的な事かもしれないのですが、上記のコードの意味が理解できず
困っております。
返り値の型 関数名strlen(引数の型);
という順番で書かれているものと思っているのですが、

返り値が下記3つ有るという事でしょうか?
・_Check_return_
・size_t
・__cdecl

また、引数const char * _Strの部分は変更不可能なchar型へのポインタ という事だと解るのですが、
_In_z_が何を意味しているのか理解できません。
---------------------------------------------------------------------------

#define _In_z_ _Pre_z_ _Deref_pre_readonly_
----------------------------------------------------------------------------
と書かれているのですが、
#define A B
でBをAで置き換えるという事だと思っているのですが、
#define A B C となっている場合はどういう意味になるのでしょうか?

投稿日時 - 2014-06-24 01:02:44

QNo.8651003

すぐに回答ほしいです

質問者が選んだベストアンサー

追記。

SALは、主に、バッファサイズを超えて書き込みされて意図しないコードを実行されてしまうなど、プログラムの脆弱性を発見する為に用いられています。

C言語では「文法上はエラーにならないが、書いても意味の無いコード」を書けてしまいます。

例えば、

void main(void)
{
bool a;
int b,c,d;
b=2,c=3,d=4;
a=b,c+d;
}

bをaに代入して、cとdを足し算していますが、足し算の結果を何処にも格納していません。計算するだけで結果を捨てています。

C言語では、文法上、上記のような書き方も許されます。

上記のように「計算だけして結果を使わずに捨てる」って書き方が文法上は可能なので

void main(void)
{
strlen("abcd");
}

と言う書き方も、文法上は可能です。

でも、こういうのは、たいていは「そのつもりが無くて、うっかり」が殆どです。

最初の例でも「<」を打つべきなのに、シフトキーを押し忘れて「,」を打っていたのです。

そこで、SALと言うのが開発され、関数の戻り値に「返り値をちゃんと使ってるか呼び出し元でチェックが必要」と言う注釈を付けたり、引数が入力か出力か、入力であればどういう内容なのか、注釈をつけたりして、文法上はエラーにならない「うっかりミス」を検出できるようにしたのです。

それらが、_Check_return_という注釈だったり、_In_z_と言う注釈だったりします。

これらの注釈が付いていれば

void main(void)
{
strlen("abcd");
}

と書いた時に「strlen()が返した結果を呼び出し側で使っていません」と言うエラーを発生させる事が可能になります。

投稿日時 - 2014-06-25 10:47:44

このQ&Aは役に立ちましたか?

9人が「このQ&Aが役に立った」と投票しています

回答(7)

ANo.6

>_In_z_ const char * _Str の様な書き方で_In_z_のような
>補足のような縛りを総称して何というのでしょうか?

「SAL注釈」と呼びます。

>constは修飾子ですよね。
>_In_z_も修飾子の一種なのでしょうか?

注釈の一種です。

SALとは「Microsoft Standard Sourecode Annotation Language」の略で、ソースコード静的解析を行う為の物で、ソースコード静的解析はソースコード内のSAL注釈を見て、ソースコードに問題が無いか報告します。

>chie65535はどうやって_In_z_がどういった役割のモノか調べたのでしょうか?
>似たような種類のモノが出てきたとき自分で解決できるように
>どこか記載されている所が有れば教えて頂きたいです。

判らなければググる。ググれば

http://d.hatena.ne.jp/i_k_b/20100226/1267200606

と言うような、非常に有用なページが見付かる。

このページには、ソースコード静的解析の使い方や起動方法や、主なSAL注釈が載っていて、書き方や意味も書いてある。

投稿日時 - 2014-06-25 10:19:02

ANo.5

>どこか記載されている所が有れば教えて頂きたいです。

#1にも#2にも書いてありますけど・・・

投稿日時 - 2014-06-25 02:33:28

ANo.4

>返り値が下記3つ有るという事でしょうか?

違います。

>・_Check_return_

戻り値を指定し、それを呼び出し元が確認する必要があることを示す。

コンパイラは関数が void なコンテキストで呼び出された(つまり、返り値を使わない書き方をした)場合「戻り値が無視されている」と言うエラーを報告する。

>・size_t

長さ、大きさ、サイズを表現する型。

そのコンパイラで「長さ、大きさ、サイズを表現できる充分なサイズがある整数の型」として、typedefで型宣言されている。

つまり、これが「戻り値の型」になる。

>・__cdecl

関数の呼出規約を指定する物。

引数をどのように渡すか、渡された引数がどう扱われるか、スタック渡しで渡した引数の後始末を呼び出された関数の中で行うか呼び出し元で行うか、引数を渡す順番を右から左にするか左から右にするか、などを決める為の物。

関数の呼び方、呼ばれ方を指示する物で、戻り値の型とは関係ない。

>引数const char * _Strの部分は変更不可能なchar型へのポインタ という事だと解るのですが、

それは間違い。メモリが変更可能なchar型へのポインタを指定しても構わない。

引数の「const 型 *」は「この関数は、関数内で、ポインタが指す内容を書き換えませんよ」って意味。

つまり「ROMなど、書き換えできないメモリのアドレスを渡しても大丈夫ですよ」って意味。

>_In_z_が何を意味しているのか理解できません。

このポインタは入力バッファ(関数にとっての入力)であり、NULL終端されている、と言う意味。

>#define A B C となっている場合はどういう意味になるのでしょうか?

これは「#define A B」です。単に「Bの中に半角スペースが入っている」だけの話。

置換後の「B」の中には、半角スペースが何個あったって構わない。

因みに「Bが半角スペースだけ」も許される。

投稿日時 - 2014-06-24 14:26:46

補足

詳しい説明大変ありがとうございました。
とても助かります。
C++の書き方に慣れていかなくてはならないのですが、
不慣れなもので、違和感がバリバリ残ってしまいます。

_In_z_ const char * _Str の様な書き方で_In_z_のような
補足のような縛りを総称して何というのでしょうか?

constは修飾子ですよね。
_In_z_も修飾子の一種なのでしょうか?

修飾子といっても宣言に移動してヘッダファイルに宣言が書かれているということは
標準の修飾子ではないのでしょうか?

chie65535はどうやって_In_z_がどういった役割のモノか調べたのでしょうか?
似たような種類のモノが出てきたとき自分で解決できるように
どこか記載されている所が有れば教えて頂きたいです。

投稿日時 - 2014-06-24 23:00:27

ANo.3

Wr5

軽くググった。

http://blog.techlab-xe.net/archives/1304
「Sourcecode Annotation Language」の為のもの…ということになりますかね。
こちらのページではVS2012から…と書かれていますが、VS2005のヘッダで既に_In_z_とかは出てきています。

投稿日時 - 2014-06-24 01:51:13

ANo.2

>返り値が下記3つ有るという事でしょうか?
>・_Check_return_
>・size_t
>・__cdecl

_Check_return_, __cdecl は戻り値の型ではないです。
ドキュメントのurlは書いて起きますが今のところは先頭が _ で始まるものについては忘れちゃってていいかも。

http://msdn.microsoft.com/ja-jp/library/984x0h58.aspx
http://msdn.microsoft.com/ja-jp/library/jj159529.aspx
http://msdn.microsoft.com/ja-jp/library/hh916382.aspx

>#define A B
>でBをAで置き換えるという事だと思っているのですが、

「A」と「B」に置き換えるです。

>#define A B C となっている場合はどういう意味になるのでしょうか?

「A」,「B」,「C」なのではなく「A」と「B C」です。
後は先に同じ

投稿日時 - 2014-06-24 01:45:46

ANo.1

Wr5

ランタイムライブラリ内部でもにょもにょする為の定義だったりしますから、あんまし気にしても仕方ないかと。

http://msdn.microsoft.com/ja-jp/library
で検索。
http://msdn.microsoft.com/ja-jp/library/78zh94ax.aspx
というページが見つかるので、「その他のバージョン▼」をクリックして2010版のものを確認すればよいかと。

>返り値が下記3つ有るという事でしょうか?
>・_Check_return_
>・size_t
>・__cdecl

_Check_return_については不明。
おそらくランタイムライブラリから戻り値があるので注意せよ。みたいなマークでしょう。
# さすがにランタイムのソース読む気にはならなかった。
# 手元のはVS2005だし。(ランタイムのソースは製品版でないと付いていない)
# デバッグビルドの時にライブリ側でチェックするのに使っているのかも知れませんね。

size_tが戻り値の型。
MSDN Library等で明示的に確認できる「利用者が必要とする情報」ですね。

__cdeclは呼び出し規約です。
「呼び出し規約」で検索すればなんぞ情報出てくるんじゃないですかね。
引数をどうスタックに積むか、戻ってきたときに引数のスタックの解放を呼び出し元がやるのか呼び出し先がやるのか…等々の規約。
呼び出し側とライブラリ側で合っていない場合に誤動作します。

>_In_z_が何を意味しているのか理解できません。

コード自体の意味はたぶんないんじゃないですかねぇ。
「この引数は入力だよ」ってことでInとなっているのかと。
# 内部で書き換えが発生する場合はOutとか、InOutとかなっていたりするでしょう。
# zは'\0'ターミネートって意味かも知れませんな。
# ハンガリアン表記でszとか書くし。

プリプロセス終わると_In_z_やらは最終的に消えていたりするんじゃないですかね。
未確認ですが。

投稿日時 - 2014-06-24 01:45:32