Знайте, если используется const квалификатор - PullRequest
4 голосов
/ 16 ноября 2011

Есть ли способ в C, чтобы найти, если переменная имеет квалификатор const? Или, если он хранится в разделе .rodata?

Например, если у меня есть эта функция:

void foo(char* myString) {...}

В этих двух разных вызовах функций должны выполняться разные действия:

char str[] = "abc";
foo(str);

foo("def");

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

Ответы [ 4 ]

4 голосов
/ 16 ноября 2011

Не в стандартном С, т.е. не переносимо.

myString - это просто char* в foo, вся остальная информация теряется. Все, что вы вводите в функцию, автоматически преобразуется в char*.

А С не знает о ".rodata".

В зависимости от вашей платформы вы можете проверить адрес в myString (если вы знаете свой диапазон адресов).

2 голосов
/ 16 ноября 2011
#include<stdio.h>
void foo(char *mystr)
{
int a;
/*code goes here*/   


#ifdef CHECK
int local_var;
printf(" strings address %p\n",mystr);
printf("local variables address %p \n",&local_var);
puts("");
puts("");
#endif
return;
}
int main()
{
char a[]="hello";
char *b="hello";
foo(a);
foo(b);
foo("hello");
}

При компиляции с помощью gcc -DCHECK prog_name.c и выполнении на моем компьютере с Linux выдается следующий вывод ...

strings address 0xbfdcacf6
local variables address 0xbfdcacc8 


strings address 0x8048583
local variables address 0xbfdcacc8 


strings address 0x8048583
local variables address 0xbfdcacc8 

для первого случая, когда строка определена и инициализирована «правильным способом c для изменяемых строк», разница между адресами составляет 0x2E (5 байт).

во втором случае, когда строка определена как char * p = "hello", различия в адресах 0xB7D82745.Это больше, чем размер моего стека. Поэтому я почти уверен, что строка не находится в стеке. Поэтому единственное место, где вы можете найти ее, это раздел .rodata.

Третий аналогичный случай

PS: Как упоминалось выше, это не переносимо, но первоначальный вопрос вряд ли оставляет место для переносимости, упоминая .rodata :)

2 голосов
/ 16 ноября 2011

Вы не можете отличить их, используя только язык.Другими словами, это невозможно без возврата к функциям, специфичным для используемого вами компилятора, который, вероятно, не будет переносимым.Несколько важных замечаний:

В первом случае вы МОЖЕТЕ изменить строку, но НЕ ДОЛЖНЫ.Если вы хотите непостоянную строку, используйте инициализация вместо назначение .

char *str1 = "abc"; // NOT OK, should be const char *
const char *str2 = "abc"; // OK, but not mutable
char str3[] = "abc"; // OK, using initialization, you can change its contents
2 голосов
/ 16 ноября 2011

GCC предоставляет встроенную функцию __builtin_constant_p, которая позволяет определить, является ли выражение постоянным или нет во время компиляции:

Встроенная функция: int __builtin_constant_p (exp)

Вы можете использовать встроенную функцию __builtin_constant_p, чтобы определить, известно ли, что значение является постоянным во время компиляции и, следовательно, что GCC может выполнять свертывание констант для выражений, содержащих это значение. Аргумент функции - это значение для проверки. Функция возвращает целое число 1, если известно, что аргумент является константой времени компиляции, и 0, если неизвестно, что это константа времени компиляции. Возвращение 0 не означает, что значение не является константой, а означает, что GCC не может доказать, что это константа с указанным значением параметра `-O '.

Так что, я думаю, вам следует переписать вашу foo функцию как макрос в таком случае:

#define foo(x) \
  (__builtin_constant_p(x) ? foo_on_const(x) : foo_on_var(x))

foo("abc") расширится до foo_on_const("abc"), а foo(str) расширится до foo_on_var(str).

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