Присвоить адрес указателя char на int

У меня есть функция, которая получает целое число в качестве параметра. Я хочу отправить ему адрес массива символов, а затем распечатать массив с его адреса. Я имею в виду:

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.

Вы можете попробовать привести указатель к int, а затем обратно к char *, но это может не сработать (неопределенное поведение). Во многих системах это невозможно, например. 64-битные системы, в которых указатель имеет длину 64 бита, а int — только 32 бита. Код будет скомпилирован, но, скорее всего, произойдет сбой при его запуске.

Nate Eldredge 16.12.2020 05:58

Зачем вам это нужно? Какую настоящую проблему вы пытаетесь решить? Способ передачи значения указателя функции заключается в использовании аргумента типа указателя.

Keith Thompson 16.12.2020 06:02

Первое, что нужно сделать, это добавить printf("%zu %zu\n", sizeof(filePointer), sizeof(x)); в свой код. Если он печатает два разных числа, то вы просто не можете сделать то, на что надеетесь.

user3386109 16.12.2020 06:03

@NateEldredge прав. Правильный способ сделать это — указать указатель на uintptr_t, который был доступен в C99 (кто-то поправит меня, если я ошибаюсь). Кроме того, приведение указателей к целым числам обычно приводит к плохим вещам.

Daniel Walker 16.12.2020 06:10
stackoverflow.com/questions/15602280/…
Support Ukraine 16.12.2020 06:42
stackoverflow.com/questions/22624737/…
Support Ukraine 16.12.2020 06:45

@KeithThompson Я хочу отправить адрес памяти в функцию, чтобы получить ее значение.

Mohammad Kholghi 20.12.2020 09:31

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

Keith Thompson 21.12.2020 00:06

Потому что функция получает целое число и является функцией общего назначения. Другие функции также передают ему целые числа. Спасибо. @КитТомпсон

Mohammad Kholghi 21.12.2020 04:51

Но почему он принимает целочисленный аргумент? Как он узнает, следует ли рассматривать его аргумент как целое число или как указатель? Спецификация в вашем вопросе делает практически невозможным то, что вы пытаетесь сделать: int часто не может содержать значение указателя. Во многих системах int имеет размер 32 бита, а указатели — 64 бита. Очевидное решение состоит в том, чтобы иметь одну функцию, принимающую целое число, и другую, принимающую указатель. Почему именно это не соответствует вашим требованиям? Я думаю, у вас проблема XY.

Keith Thompson 21.12.2020 06:44
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
10
977
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Лучший способ, который я мог бы придумать, сделать это, учитывая, что вы не хотите просто передавать указатель на массив, - это привести его к 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 определить раздел по низкому адресу памяти. Этот ответ делает что-то в этом роде. Это, вероятно, тоже не портативно.

Другие вопросы по теме