2

const私はキーワードについて非常に混乱しています。文字列の配列を入力パラメーターとして受け入れる関数と、可変数の引数を受け入れる関数があります。

void dtree_joinpaths(char* output_buffer, int count, ...);
void dtree_joinpaths_a(char* output_buffer, int count, const char** paths);

dtree_joinpathsdtree_joinpaths_a引数リストから文字列の配列を作成した後、内部的に呼び出します。

void dtree_joinpaths(char* output_buffer, int count, ...) {
    int i;
    va_list arg_list;
    va_start(arg_list, count);
    char** paths = malloc(sizeof(char*) * count);
    for (i=0; i < count; i++) {
        paths[i] = va_arg(arg_list, char*);
    }
    va_end(arg_list);
    dtree_joinpaths_a(output_buffer, count, paths);
}

しかし、gccコンパイラは次のエラーメッセージを表示します。

src/dtree_path.c: In function 'dtree_joinpaths':
src/dtree_path.c:65: warning: passing argument 3 of 'dtree_joinpaths_a' from incompatible pointer type

に変更char** paths = malloc(count);するとconst char** paths = malloc(count);、このエラーは表示されなくなります。私が理解していないのは、それです

  1. アドレスへのポインターは常にconstポインターにキャストできると思いましたが、その逆はできません(これは、ここでimoで起こっていることです)。
  2. この例は機能します:http://codepad.org/mcPCMk3f

私は何を間違っているのですか、それとも私の誤解はどこにありますか?


編集

私の意図は、入力データのメモリを関数に対して不変にすることです。(この場合はpathsパラメーター)。

4

4 に答える 4

5

char **->const char**が「危険な」変換である理由は、次のコードです。

const char immutable[] = "don't modify this";

void get_immutable_str(const char **p) {
    *p = immutable;
    return;
}

int main() {
    char *ptr;
    get_immutable_str(&ptr); // <--- here is the dangerous conversion
    ptr[0] = 0;
}

const char上記のコードは、未定義の動作である変更不可能なオブジェクト(のグローバル配列)を変更しようとします。このコードには、「不良」と定義する候補が他にないため、const-safetyは、ポインター変換が不良であることを示します。

Cは変換を禁止していませんがgcc、それが悪いことを警告します。参考までに、C ++は変換を禁止しており、Cよりも厳密なconst-safetyを備えています。

この例では文字列リテラルを使用しましたが、Cの文字列リテラルはそもそも「危険」です。変更することはできませんが、型がarray-of-charではなくarray-of-const charです。これは歴史的な理由によるものです。

アドレスへのポインタは常にconstポインタにキャストできると思いました

非const-Tへのポインタはconst-Tへのポインタに変換できます。char **->const char**はそのパターンの例ではありません。なぜなら、そうである場合はTそうではないからです(この時点では、左側にをもう書かないことはおそらく価値があります。書くと、Tがどこにあるかと同じになるとは期待できません。 )。char *const Tchar * constconst char *constchar const *T constchar *

に安全に変換できchar **char * const *(単純なルールよりも少し多くを必要とする理由で)安全にに変換できchar **ますchar const * const *

于 2013-01-21T16:56:23.260 に答える
1

重要なのは、ポインタがconstではないということです。char *const ptr;constポインターを宣言するには、またはを使用してconstポインターをconstポインターに宣言しますchar *const *const ptr;const char **ptrへのポインタへのポインタconst charです。

于 2013-01-21T15:35:27.483 に答える
0

実際、const char **を受け入れる関数があり、char **を渡すと、問題のある状況やその逆につながる可能性があります。

特定のケースでは、メモリは不変であると予想しますが、不変ではなく、いつでも変更される可能性があります。マルチスレッド環境では、このメモリがスレッドセーフであることが期待され、スタックまたはヒープに存在する限り、アクセスするためにミューテックスは必要ありません。

これはすべてエラーを回避することを目的としていますが、これでエラーが発生しないことが確実な場合は、ポインターをconstchar**にキャストするだけです。

于 2013-01-21T15:57:49.047 に答える
0

コンパイラはconstの正当性を保証できないため、渡すことはchar **できません。const char **

次のコード(およびコンパイル済み)があるとします。

void foo(const char **ppc, const char* pc)
{
  *ppc = pc; // Assign const char* to const char*
}

void bar()
{
  const char c = 'x';
  char* pc;

  foo(&pc, &c); // Illegal; converting const char* to const char**. Will set p == &c
  *pc = 'X';    // Ooops! That changed c.
}

関数呼び出しのない同じ例については、ここを参照してください。

于 2013-01-21T16:55:57.050 に答える