У меня есть функция, которая получает целое число в качестве параметра. Я хочу отправить ему адрес массива символов, а затем распечатать массив с его адреса. Я имею в виду:
void printSomeThing(int x){
printf("Variable is: %s\n", /*What to type here?*/);
//I want this printf to write "file.txt"
}
....
int main(){
char filename[10] = "file.txt";
char *filePointer = filename; //So it points to filename[0]'s address.
int x = /*How to convert the address of the pointer (or the char array) to an integer?*/
printSomeThing(x);
}
Итак, я хочу отправить адрес массива символов в функцию и распечатать значение этого адреса.
ПРИМЕЧАНИЕ. Я не могу изменить параметр printSomeThing. Это должно быть int.
Зачем вам это нужно? Какую настоящую проблему вы пытаетесь решить? Способ передачи значения указателя функции заключается в использовании аргумента типа указателя.
Первое, что нужно сделать, это добавить printf("%zu %zu\n", sizeof(filePointer), sizeof(x)); в свой код. Если он печатает два разных числа, то вы просто не можете сделать то, на что надеетесь.
@NateEldredge прав. Правильный способ сделать это — указать указатель на uintptr_t, который был доступен в C99 (кто-то поправит меня, если я ошибаюсь). Кроме того, приведение указателей к целым числам обычно приводит к плохим вещам.
@KeithThompson Я хочу отправить адрес памяти в функцию, чтобы получить ее значение.
Да, очевидно, это то, что вы хотите сделать. Но если функции нужен адрес для передачи в качестве аргумента, почему функция не определяет свой параметр с типом указателя? (Есть некоторые редкие случаи, когда определение функции с целочисленным аргументом, которая затем обрабатывает этот аргумент как значение адреса, имеет смысл. Вы не сказали ничего, что указывало бы, почему вам нужно это сделать.)
Потому что функция получает целое число и является функцией общего назначения. Другие функции также передают ему целые числа. Спасибо. @КитТомпсон
Но почему он принимает целочисленный аргумент? Как он узнает, следует ли рассматривать его аргумент как целое число или как указатель? Спецификация в вашем вопросе делает практически невозможным то, что вы пытаетесь сделать: int часто не может содержать значение указателя. Во многих системах int имеет размер 32 бита, а указатели — 64 бита. Очевидное решение состоит в том, чтобы иметь одну функцию, принимающую целое число, и другую, принимающую указатель. Почему именно это не соответствует вашим требованиям? Я думаю, у вас проблема XY.



Лучший способ, который я мог бы придумать, сделать это, учитывая, что вы не хотите просто передавать указатель на массив, - это привести его к unsigned long, чтобы передать его функции.
Однако ваш компилятор может жаловаться, что вы передаете целочисленное значение в строковый шаблон в printf, но это в силу используемого вами дизайна.
Если вам не нужно использовать printSomeThing(int i), просто передайте сам char* или используйте void*, если вам нужны другие вещи, которые были переданы, и используйте какой-то флаг, чтобы сообщить функции, какой тип вы передали
Правильный способ преобразования между адресами указателей и целыми числами — использовать целочисленный тип uintptr_t. Это тип, который гарантированно будет достаточно большим для хранения адреса (в отличие от int). Этот код достаточно безопасен и переносим:
#include <stdio.h>
void printSomeThing(uintptr_t x){
printf("Variable is: %s\n", (char*)x);
}
int main(){
char filename[10] = "file.txt";
char *filePointer = filename; //So it points to filename[0]'s address.
uintptr_t x = (uintptr_t)filePointer;
printSomeThing(x);
}
Если sizeof(int) != sizeof(char*), то то, что вы пытаетесь сделать, вообще невозможно.
Тем не менее, есть способ заставить эту работу работать. Прежде чем я расскажу вам, как этого добиться, позвольте мне повторить то, что говорили другие: вы не должны использовать int в качестве указателя. Это не очень хорошая идея. То, что я собираюсь продемонстрировать, — это просто демонстрация. То, что это можно сделать, не означает, что это нужно делать.
Один из способов сделать это — отобразить память по адресу меньше 1 << (sizeof(int) * 8). Затем скопируйте нужную строку в эту ячейку памяти. Теперь вы можете передать этот указатель своей функции printSomething(int).
У этого решения есть одна проблема: оно не переносимо, поэтому не всегда работает. Я не смог заставить его работать с clang на macOS, но здесь он работает . Вот код, который я использовал.
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
void printSomething(int x){
printf("Variable is: %s\n", (char*) x);
}
int main(){
char filename[10] = "file.txt";
char *allocd = mmap((void*) 0x10000, sizeof(filename)+1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
strcpy(allocd, filename);
printSomething((int) allocd);
}
Другое решение, которое, вероятно, следует использовать только в качестве демонстрации, — это то, где вы просите gcc определить раздел по низкому адресу памяти. Этот ответ делает что-то в этом роде. Это, вероятно, тоже не портативно.
Вы можете попробовать привести указатель к
int, а затем обратно кchar *, но это может не сработать (неопределенное поведение). Во многих системах это невозможно, например. 64-битные системы, в которых указатель имеет длину 64 бита, аint— только 32 бита. Код будет скомпилирован, но, скорее всего, произойдет сбой при его запуске.