Как функция обнаруживает строковый указатель против строкового литерала? - PullRequest
2 голосов
/ 26 августа 2010

Я столкнулся с функцией, так что она может различать вызов как

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"

У меня нет доступа к коду функции, и объявления в заголовочном файле показывают только одно объявление функции.

Ответы [ 3 ]

5 голосов
/ 27 августа 2010

Вот еще один способ различения строкового литерала и указателя, основанный на том факте, что строковые литералы имеют тип массива, а не тип указателя:

#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 бесполезен, потому что RTTI существует только для классов с хотя бы одной виртуальной функцией-членом.Все остальное зависит от реализации: в стандарте нет гарантии, что строковые литералы будут занимать какую-либо конкретную область памяти или что один и тот же строковый литерал, использованный дважды в программе (или даже в модуле компиляции), будет иметь один и тот же адрес.С точки зрения места хранения, все, что реализация может делать со строковыми литералами, разрешено также делать с моим массивом a.

0 голосов
/ 26 сентября 2013

Теоретически функция foo() может использовать макрос для определения, является ли аргумент литералом или нет.

#define foo(X) (*#X == '"'
                ? foo_string_literal(X)
                : foo_not_string_literal(X))
0 голосов
/ 26 августа 2010

И что произойдет, если вы называете это следующим образом:

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

Вероятно, для определения используется, вероятно, какое-то различие, подобное этому.

РЕДАКТИРОВАТЬ: если в функции есть только одно объявление функциизаголовок, который я не могу представить ни одним переносимым способом, которым библиотека могла бы сделать это различие.

...