#c #variables #int
#c #переменные #int
Вопрос:
Допустим, у меня есть переменная:
int fish5 = 7;
Могу ли я получить доступ к fish5 путем объединения терминов «fish» и «5» каким-либо образом?
Идеальное решение выглядело бы примерно так:
printf("I am displaying the number seven: %i", fish 5);
Комментарии:
1. Предполагается, что это должно работать во время выполнения или компиляции? Во время компиляции это возможно с помощью препроцессора. Во время выполнения это невозможно.
2. Более логичным сценарием является сохранение переменных (fish1, fish2, …) в векторе / массиве и использование индекса для его извлечения. fishes[4] будет пятой рыбой.
3. Сохраните их в массиве и используйте индекс для его извлечения, смотрите Ответ Константина (и мой комментарий здесь)
4. @user3800357: тогда покажите нам контекст. Люди во всем мире каким-то образом используют cuda без этой проблемы 😉
5. @user3800357 Возможно, вы захотите добавить некоторую информацию относительно части CUDA, поскольку требования отличаются .
Ответ №1:
Нет, не совсем то, что вы хотите. Но в вашем примере вы можете использовать массив (работает, только если вы хотите объединить имя переменной с числом):
int fish[6] = {0};
fish[5] = 7;
printf("I am displaying the number seven: %i", fish[5]);
Смотрите также здесь ссылку на массивы в C .
Другим решением было бы использовать std::map
вместо этого, как указано Thrustmaster в комментариях.
Затем вы могли бы написать что-то вроде:
#include <map>
#include <string>
int main(int argc, char* argv[]){
std::map<std::string, int> map;
map.insert(std::make_pair("fish5", 7));
printf("I am displaying the number seven: %d", map[std::string("fish") std::to_string(5)]);
return 0;
}
Для получения дополнительной информации о std::map
смотрите здесь.
Комментарии:
1. @Thrustmaster было бы нелогично каждый раз сохранять имя ‘fish<nr>’, почему бы просто не указать значение и не использовать для него вектор / список?
2. @Constantin У меня была такая же идея, что это сценарий, который нужен пользователю.
3. @Thrustmaster Спасибо, я добавил то же самое с помощью
std::map
.4. Если поддерживается, вероятно, было бы лучше использовать
std::unordered_map
здесь.
Ответ №2:
Невозможно перевести решение из времени компиляции во время выполнения, потому что c — это скомпилированный язык, а не интерпретируемый. Имена переменных «теряют свое значение» после компиляции. Это просто набор символов с адресами. Это означает, что после компиляции запрашивать что-то вроде fish5
не имеет смысла.
Чтобы достичь желаемого, вам нужно каким-то образом программно привязать имя к объекту, например, с помощью карты, которая хранит имена в виде ключей, а ссылки на объекты — в виде значений. Вот как python это делает, и почему в python вы действительно можете получить доступ к объекту через его имя из кода.
На случай, если кому-то интересно, почему, например, gdb или аварийные дампы имеют смысл, это практически по той же причине. Имена символов должны быть сохранены во время компиляции (либо встроены в исполняемый файл, либо во внешний файл), тогда внешний инструмент может выяснить, как называется переменная по определенному адресу. Но скомпилированный исполняемый файл может прекрасно работать и без этой информации.
В качестве альтернативы вам нужно запомнить саму ссылку каким-либо более удобным способом, который позволяет ей быть вычислимой. Например. сохраните ее в массиве и получите доступ как fish[5]
; хотя в этом примере она может быть вычислена во время компиляции, вы можете использовать тот же метод во время выполнения, используя переменную вместо 5
.
Различие между временем компиляции и временем выполнения очень важно, потому что вы действительно можете делать то, что хотите во время компиляции с помощью препроцессора, но только потому, что это время компиляции.
Комментарии:
1. Это может быть возможно (получить доступ к переменной по ее имени во время выполнения) с использованием специфичных для операционной системы приемов. Смотрите мой ответ.
2. Я думаю, что это описано в части «как работает gdb», но я могу указать это явно, если это непонятно. Я также думаю, что передавать этот механизм опасно или, по крайней мере, довольно сомнительная практика, но, тем не менее, возможная.
Ответ №3:
Вы могли бы использовать специфичные для операционной системы вещи, такие как (в Posix, например, Linux) dlsym(3) для доступа к переменным через таблицу символов внутри (без ограничений) исполняемого файла ELF во время выполнения.
Итак, предпочтительно объявлять переменные, к которым вы хотите получить доступ, по их имени как extern "C"
например
extern "C" int fish17;
(в противном случае примите во внимание искажение имени, специфичное для компилятора)
Объявите также дескриптор программы:
void *progdlh;
инициализируйте ее в начале main
progdlh = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
if (!progdlh) { fprintf(stderr, "dlopen failure %sn", dlerror());
exit(EXIT_FAILURE); }
затем, чтобы получить вашу переменную по вычисляемому имени, вы можете попробовать:
char nambuf[32];
snprintf (nambuf, sizeof(nambuf), "%s%d", "fish", 17);
int *pvar = dlsym(progdlh, nambuf);
if (!pvar) { fprintf(stderr, "dlsym %s failure %sn", nambuf, dlerror());
exit(EXIT_FAILURE); }
printf ("variable %s is %dn", nambuf, *pvar);
Вероятно, вам следует связать свою программу с -rdynamic
флагом (и с -ldl
библиотекой)
Мой ответ должен работать в Linux.
Комментарии:
1. 1 Общий подход является разумным, но использование
printf
функций семейства над потоками …? ;-P
Ответ №4:
Вы можете сделать это только во время компиляции, используя препроцессор. Полный пример:
#include <cstdio>
#define JOIN(a,b) a##b
int main(void) {
int fish5 = 5;
std::printf("I am displaying the number five: %i", JOIN(fish, 5));
return 0;
}
Однако это строго время компиляции. Если вы попытаетесь, JOIN(fish, fish)
вы получите error: ‘fishfish’ undeclared
, и если вы попытаетесь, JOIN("fish", fish)
вы получите error: pasting ""fish"" and "fish" does not give a valid preprocessing token
.
В C имена переменных не существуют во время выполнения, поэтому операция не может быть выполнена во время выполнения, за исключением того, что требуется некоторая глубокая отладочная информация для поиска переменных по их строке имени (как это делает debugges). Если использование строк является допустимым подходом для вас, тогда лучше просто явно отобразить строку на адрес переменной. Другие ответы показывают, как это уже сделать, используя std::map
.