2009-06-14 16 views
13

strtol、strtodは危険ですか?

strtod()は効果的にあなたが文字列内のconstnessをキャストすることを許しているようです:

#include <stdlib.h> 
#include <stdio.h> 

int main() { 
    const char *foo = "Hello, world!"; 
    char *bar; 
    strtol(foo, &bar, 10); // or strtod(foo, &bar); 
    printf("%d\n", foo == bar); // prints "1"! they're equal 
    *bar = 'X'; // segmentation fault 
    return 0; 
} 

上では、自分でキャストを実行しませんでした。しかし、strtol()は、基本的に私のconst char *char *にキャストし、警告や何もせずに。 (実際には、barconst char *とタイプすることができないため、タイプの安全でない変更が強制されます)。それは本当に危険ではありませんか?

答えて

13

私が推測するのは、代替案が悪かったからです。プロトタイプがconstを追加するために変更されたと仮定します。

long int strtol(const char *nptr, const char **endptr, int base); 

、我々は非定数文字列を解析するとします。

char str[] = "12345xyz"; // non-const 
char *endptr; 
lont result = strtol(str, &endptr, 10); 
*endptr = '_'; 
printf("%s\n", str); // expected output: 12345_yz 

しかし、我々は、このコードをコンパイルしようとするとどうなりますか?コンパイラエラー!むしろ直感的ではありませんが、char **を暗黙的にconst char **に変換することはできません。理由の詳細については、C++ FAQ Liteを参照してください。 C/C++では、 "タイプへのポインタ"から "constタイプへのポインタ"に最高レベルで暗黙的に変換することのみが許可されています:あなたが実行できる変換はchar **からchar * const *までであるか、または "ポインタ(charへのポインタ)から"(constへのポインタ)へのポインタ "から" charへのポインタ "です。

定数でない文字列を解析するのは、定数文字列を解析するよりもはるかに多いと思われますので、私はこれを仮定します。const一般的なケースをコンパイラエラーにすることは好ましくありません。

+4

しかし、C++は関数のオーバーロードを防ぎません:long int strtol(char * nptr、char ** endptr、int base); '*と*' long int strtol(const char * nptr、const char ** endptr、int base); ':これはあなたのコンパイルエラーを修正します。実際には、標準では 'strchr'や' strstr'のような他の関数のためにこれを行なっています。 – Thanatos

+0

CのFAQ Webサイト['const char * p'と' char const * p'との違いは何ですか? 'char * const p'?](http://c-faq.com/ansi/constptrconst.html)を参照してください。特に、 '' char ** 'を '' ' const char ** '?](http://c-faq.com/ansi/constmismatch.html)をC++ FAQの代わりに使用していますが、説明が分かりやすいと私は完全には思っていません。 –

1

最初の引数の 'const char *'は、strtol()が文字列を変更しないことを意味します。

返されたポインタの処理は、あなたのビジネスです。

はい、型の安全違反と見なすことができます。 C++は多分やり方を変えるでしょう(ただし、ISO/IEC 14882:1998はCと同じ署名で<cstdlib>を定義しています)。

+0

C++は、Cと同じシグネチャでstrtol(およびcstdlibの他のすべて)を定義しますが、cstringとcwcharのすべてを定義するわけではありません。 –

6

はい、その他の機能には同じ "const-laundering"の問題があります(strchr、strstrなど)。関数のシグネチャstrchr(const char*, int)は、2つの宣言に置き換えます:

const char* strchr(const char* s, int c); 
     char* strchr(  char* s, int c); 

しかし、Cで、もちろんあなたは、両方のconst-正しいバージョンを持つことはできませんC++は(:4 21.4)のオーバーロードが追加されますまさにこの理由のため

同じ名前で、あなたはconst-incorrectの妥協を得るでしょう。

C++にはstrtolとstrtodに似たオーバーロードはありませんが、実際には私のコンパイラ(GCC)にはそれらがありません。私はなぜわからないのですか:char**const char**にキャストすることはできません(オーバーロードの不在とともに)Cについて説明していますが、C++のオーバーロードで何が間違っているかはわかりません。

long strtol(const char*, const char**, int); 
+1

stlportはこのオーバーロード(および他のもの)を提供します。 –

1

C++モードでコンパイルするとき、私は、提供してコンパイラを持っている:明らか

extern "C" { 
long int strtol(const char *nptr, const char **endptr, int base); 
long int strtol(char *nptr, char **endptr, int base); 
} 

これらの両方が同じリンク時のシンボルに解決。

EDIT:C++標準に従って、このヘッダーはコンパイルしないでください。私はコンパイラが単にこれをチェックしていないと推測しています。定義は実際にはシステムヘッダーファイルにこのように表示されました。

関連する問題