2

次のように呼び出されることを区別できる関数に遭遇しました

foo("bar");

const char *bob = "bar";
foo(bob);

私が考えた可能性は次のとおりです。

  • 文字列のアドレス: 両方の引数がイメージの .rdata セクションにありました。同じプログラムで両方の呼び出しを行うと、両方の呼び出しが同じ文字列アドレスを受け取ります。
  • RTTI: RTTI を使用してそのような違いを検出する方法がわかりません。

私が思いつく唯一の実用的な例は次のとおりです。

void foo(char *msg)
{
    printf("string literal");
}

void foo(const char *&msg)
{
    printf("string pointer");
}

foo("bar");                 // "string literal"

const char *soap = "bar";
foo(soap);                  // "string pointer"

関数のコードにアクセスできず、ヘッダー ファイル内の宣言から 1 つの関数宣言しか明らかになりませんでした。

4

3 に答える 3

5

文字列リテラルにはポインタ型ではなく配列型があるという事実に基づいて、文字列リテラルとポインタを区別する別の方法を次に示します。

#include <iostream>

void foo(char *msg)
{
    std::cout << "non-const char*\n";
}

void foo(const char *&msg) // & needed, else this is preferred to the
                           // template function for a string literal
{
    std::cout << "const char*\n";
}

template <int N>
void foo(const char (&msg)[N])
{
    std::cout << "const char array reference ["<< N << "]\n";
}

int main() {
    foo("bar"); // const char array reference [4]
}

ただし、文字列リテラルではないものを渡すことで、それらすべて(元の関数を含む)を「だます」ことができることに注意してください。

const char *soap = 0;
foo(soap);

char *b = 0;
foo(b);

const char a[4] = {};
foo(a);

C ++には、文字列リテラルに固有の型はありません。したがって、型を使用して配列とポインタの違いを区別することはできますが、文字列リテラルと別の配列の違いを区別することはできません。RTTIは、少なくとも1つの仮想メンバー関数を持つクラスにのみ存在するため、使用できません。それ以外は実装に依存します。標準では、文字列リテラルがメモリの特定の領域を占有することや、プログラム(またはコンパイルユニット)で2回使用される同じ文字列リテラルが同じアドレスを持つことは保証されません。格納場所に関しては、実装が文字列リテラルで実行できることはすべて、私の配列でも実行できますa

于 2010-08-26T23:38:01.997 に答える
1

理論的には、関数foo()はマクロを使用して、引数がリテラルかどうかを判断できます。

#define foo(X) (*#X == '"'
                ? foo_string_literal(X)
                : foo_not_string_literal(X))
于 2013-09-25T21:45:21.603 に答える
0

そして、次のように呼び出すとどうなりますか。

const char bob[] = "bar";
foo(bob);

そういう区別をつけて判断しているのだろう。

編集:ヘッダーに関数宣言が1つしかない場合、ライブラリがその区別を行う移植可能な方法を思いつきません。

于 2010-08-26T17:27:27.850 に答える