C - принудительное использование строкового параметра в постоянной памяти - PullRequest
0 голосов
/ 13 сентября 2018

Я оптимизирую некоторый код, и у меня есть такая функция:

const char * gStrPtr = NULL;

void foo (const char *str) {
     gStrPtr = strdup(str);
}

На данный момент foo() вызывается только с константными строками. например:

const char fooStr[]="Some really long string...";
foo(fooStr);

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

void foo (const char *str) {
     gStrPtr=str;
}

Но это открывает острую палку: если кто-то в будущем нарушит соглашение и попытается вызвать foo() с динамической копией строки, которая позже освобождается, это может вызвать неопределенное поведение.

Мне интересно, возможно ли создать во время компиляции или даже во время выполнения проверку, которая проверяет, находится ли str в памяти только для чтения, чтобы избежать дорогостоящих ошибок в будущем.

Примечание: если я предполагаю, что str является строковым литералом, то я могу сделать это с помощью макроса следующим образом:

#define foo(str)  foo_func("" str)

, что приведет к ошибкам компиляции не-строковых литералов. Но он также не принимает указатели на константные символы.


EDIT

Я думал, что выложу это после обсуждения ниже. @CraigEtsy указал на использование __builtin_constant_p, который является наилучшим способом решения этой проблемы (но, вероятно, будет достаточным для моих нужд). Я сделал следующие тесты с этим, и получил эти результаты:

void foo(const char *str) {
        if (__builtin_constant_p(*str))
                printf("%s is constant\n", str);
        else
                printf("%s is not constant\n", str);
}

const char globalArray[] = "globalArray";
const char *globalPtr = "globalPtr";

int main()
{
    const char localArray[]="localArray";
    const char *localPtr="localPtr";
    char localNonConst[]="localNonConst";
    foo("literal");     // constant
    foo(localArray);    // not constant
    foo(localPtr);      // constant
    foo(globalArray);   // constant
    foo(globalPtr);     // not constant
    foo(localNonConst); // not constant
}

И при компиляции с -O3 он дал результаты:

literal is constant
localArray is not constant
localPtr is constant
globalArray is constant
globalPtr is not constant
localNonConst is not constant

Итак, для моего конкретного случая я могу просто переключить const char arr[]="str" на const char * arr="str", а затем, в своем foo(), я могу проверить, является ли значение постоянным, а также выделить память и увеличить время выполнения. предупреждение, если нет (и пометьте флаг, чтобы я знал, нужно ли освобождать указатель позже ...).

1 Ответ

0 голосов
/ 13 сентября 2018

Я не думаю, что есть какой-то разумный способ обеспечить это во время выполнения, по крайней мере, не без оборудования, которое было бы на много порядков дороже, чем просто вызов strdup.

Если функция должна принимать только неизменяемые строки в качестве аргументов (это слово, которое вы ищете - неизменяемое, в том смысле, что ее время жизни будет оставшейся частью времени жизни процесса и его содержимое не изменится до конца срока службы), это должно быть документированной частью контракта на интерфейс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...