2016-01-13 13 views
8

http://www.cplusplus.com/reference/cstdlib/strtol/によれば、この機能はlong int strtol (const char* str, char** endptr, int base)の署名を持っています。strtolをconst-correctnessでどのように実装しますか?

文字列の先頭にconst char *が渡された場合、その文字を非定数ポインタに変換する方法はどうですか? strtolの実装はconst_castを実行しません。

+0

ベースのstrの方向をオフセットとした「再生」はどうですか? – kazbeel

+3

それは 'const char ** endptr'をとり、そうでなければ等しい実装を持ちますが、http://stackoverflow.com/questions/993700/are-strtol-strtod-unsafeを参照してください。 –

+2

答えは「できません」です。しかしこれは別のより一般的な質問で答えられました。 – dasblinkenlight

答えて

2

ほとんどの場合、キャストが使用されています。

標準ライブラリに同じプロパティを持つ関数があります。あなたがC++のように関数をオーバーロードすることはできないので、シンプルさより型の安全性を犠牲にしているのはおそらく理由でしょう。

プログラマーが責任を負うことを期待しており、たとえばstrが文字列リテラルの場合はendptrを編集しません。

制限されたタイプのシステムでは、Cは実用的な人にとって実用的な言語です。

1

strtolは、const_cast(または同等のもの)です。 constをキャスティングすることは問題ではありません。元のポインタを修正するために結果のポインタを使用して、constかもしれません。

しかしstrtolはちょうどそれをいじることなく、あなたにこのポインタを返すので、すべてが正常です。

+1

すべてが問題ではありません。 const配列へのポインタを 'strtol'に渡し、その結果の' * endptr'ポインタを使ってその配列を変更することができます。これはC標準ライブラリの欠陥です。 –

+0

@KeithThompsonとのトレードオフが行われました。より安全なインターフェイスのために、種類の安全性が欠けています。それでも、スタンダードの視点からは、UBやその他の危険性はありません。 – Quentin

+0

答えのサンプルプログラムを見てください。関数自体は 'const'安全性に違反しませんが、キャストや警告なしでそれを使用するユーザコードを可能にします。より良いインターフェースは2つの異なる機能を提供し、1つは 'const'データ用で、もう1つは非'コンステート 'データ用です。 –

1

どのようにconstの-正し下strtolはを実装していますか? C11 _Generic

のみを使用して関数のシグネチャの保存が必要とされるように同一である、以下のように、コードは

// when passed argument for `str` is `char *` and for `endptr` is `char **` 
long strotol(const char* str, char** endptr, int base); 
// or 
// when passed argument for `str` is `const char *` and for `endptr` is `const char **` 
long strotol_c(const char* str, const char** endptr, int base); 
// and warn/error otherwise 

実装のいずれかを呼び出すことができるようになります。これはstrtol()とは異なるので、strtol_s()のような別のものと呼ぶべきです。 strtol_s()は真の関数ではありませんので、それへのポインタはできません。失われた何

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

long int strtol_c(const char * restrict nptr, const char ** restrict endptr, int base) { 
    return strtol((char *) nptr, (char **) endptr, base); 
} 

#define strtol_s(n,e,b) _Generic(n, \ 
    char *: strtol((n), (e), (b)), \ 
    const char *: strtol_c((n), (e), (b)), \ 
    default: 0 \ 
) 

int main(void) { 
    char *src = malloc(100); 
    strcpy(src, "456"); 
    const char *srcc = "123"; 
    char *endptr; 
    const char *endcptr; 
    long L[6] = { 0 }; 

    // OK - matching str and *endptr 
    L[0] = strtol_s(src, &endptr, 0); 

    // warning: passing argument 2 of 'strtol' from incompatible pointer type 
    L[1] = strtol_s(src, &endcptr, 0); 

    // warning: passing argument 2 of 'strtol_c' from incompatible pointer type 
    L[2] = strtol_s(srcc, &endptr, 0); 

    // OK - matching str and *endptr 
    L[3] = strtol_s(srcc, &endcptr, 0); 

    L[4] = strtol(src, &endptr, 0); 
    // warning passing argument 2 of 'strtol' from incompatible pointer type 

    // OK 
    L[5] = strtol(src, &endcptr, 0); 
    return !L[0]; 
} 

浮動小数点数なしで最初の未処理文字への非constポインタに変換するにはどうすればよいですか?

strtol()、それは2番目の引数としてchar **endptrがかかりますが、*endptrを変更しません。

4

strtolをconst-correctnessで実装するにはどうすればよいですか?

strtolの定義は、本質的にconst -correctではありませんので、あなたは、しないでください。

これはC標準ライブラリに欠陥があります。

const char*引数をとるいくつかの標準関数があります(文字配列の先頭を指し示すと予想されます)。その配列を変更するために使用できる非constchar*ポインタを戻します。

strchrは一例であり、例えば:

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

#include <string.h> 
int main(void) { 
    const char *s = "hello"; 
    char *ptr = strchr(s, 'h'); 
    *ptr = 'H'; 
} 

このプログラムは未定義の動作をしています。私のシステムでは、セグメンテーション違反で死にます。

strchrでは問題は発生しません。あなたが渡した文字列を変更しないことを約束します。しかし、呼び出し元がそれを変更するために使用できるポインタを返します。

ANSI C委員会、バック1980年代後半に、二つのバージョン、非constアレイ用const文字配列と別に作用するものに、そのような各機能を分割することができた:

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

しかし、それは既存のANSIコードを壊してしまい、constの前に書かれていました。これは、Cが文字列リテラルを作成しなかったのと同じ理由であるconstです。

Cの標準ライブラリのほとんどを継承するC++は、いくつかの関数のオーバーロードされたバージョンを提供することでこれを処理します。

は、Cプログラマとしてconstとして定義したオブジェクトを変更しないようにしています。ほとんどの場合、この言語はあなたがこれを強制するのを助けますが、必ずしもそうではありません。

これらの関数がconstデータへのポインタを返す方法については、内部でキャストを使用するだけです(C++でのみ存在するconst_castではなく)。これはC言語で実装されていると想定していますが、これは必須ではない可能性があります。

関連する問題