В C Как установить значение для одного адреса в значение для другого адреса? - PullRequest
0 голосов
/ 17 марта 2020

Я пытаюсь создать некоторый код UART, который поместит небольшую строку в стек для передачи через систему прерываний. Это специально для микроконтроллера Atmel SAM

#define UART_BUF_LEN 16

//GPS SERIAL INSTANCE
struct usart_module usart_instance; 
char buffer[UART_BUF_LEN];
uintptr_t bufferPtr = (uintptr_t)buffer;

bool transmitting(){
    return (uintptr_t)buffer == bufferPtr; //If the read head is at the top of the array, then we are not transmitting.
}

bool transmit(char* c, uint len){
    if(!transmitting() && len<=UART_BUF_LEN){
        bufferPtr= (uintptr_t)buffer + len;//set write head to top of the len stack
        while(transmitting()){
            *bufferPtr = *c; //Set the value at the address of bufferPtr to the value at the address of c.
            bufferPtr --; //Move the buffer closer to the head of the array
            c++; //Move the head of the array down some.
        }
    }else{
        return false;
    }
    bufferPtr= (uintptr_t)buffer + len; //reset the read head so that our transmit code knows where to read from.
    return true;
}

Проблема здесь в линии *bufferPtr = *c;. Когда я строю решение, bufferptr кажется не разыменованным. Я получаю следующую ошибку:

недопустимый аргумент типа унарного '*' (have 'uintptr_t {aka unsigned int}')

Я смотрел онлайн, и все источники говорят мне, что я должен привести uintptr_t обратно к указателю собственного типа данных, на который указывает адрес памяти. Я не уверен, как это сделать, так как использование typecast (char *), указывающего, что указатель буфера является символьным указателем, не компилируется, что выдает мне ту же ошибку, что и выше.

Теперь кроличья нора становится на один уровень глубже, когда я изменяю линию на \*(char\*)bufferPtr = \*c;, что не дает мне никакой ошибки. Что означает эта строка?

Я ожидаю, что это означает, что значение по адресу типа typecast в bufferPtr для указателя на символ установлено в значение по адресу c. Это правильно?

Ответы [ 3 ]

2 голосов
/ 17 марта 2020

Поскольку bufferPtr является uintptr_t, который является целочисленным типом, а не типом указателя, вам придется преобразовать его обратно в тип указателя перед разыменованием его.

*(char *)bufferPtr = *c;

Это хорошо, поскольку источником значения bufferPtr является массив char.

char buffer[UART_BUF_LEN];
uintptr_t bufferPtr = (uintptr_t)buffer;
0 голосов
/ 17 марта 2020

uintptr_t - это тип integer , который позволяет безопасно хранить значение указателя в целом числе. Поскольку разные машины и архитектуры имеют разные размеры указателей, этот тип позволяет преобразовывать указатель в целочисленный тип, не беспокоясь о выборе правильного размера целого числа (например, 32-битных или 64-битных целых) в зависимости от машины. Это облегчает написание переносимого кода.

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

char* char_ptr = (char*)bufferptr;
*char_ptr =  *c;  

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

Поскольку размер char гарантированно равен 1, все вычисления, которые вы выполняете на char*, точно такие же, как вычисления, которые вы выполняете для целого числа, например

char c = 'A'
char* p0 = &c;
uintptr_t p_casted = (uintptr_t)p0;

char* p1 = p0 + 42;
char* p2 = (char*)(p_casted + 42);

В этом примере p1 и p2 будут иметь точно такое же значение. p0 + 42 добавит в 42 раза размер char к адресу, содержащемуся в p0, но, поскольку размер char всегда равен 1, это точно так же, как и во второй версии.

Результат будет другим для типа, размер которого не равен 1 (например, если p0 было int* или float*). Однако, если вы хотите выполнять простые целочисленные вычисления (скажем, добавлять или вычитать смещение) к значению указателя, я все равно рекомендовал бы приведение к char* вместо intptr_t, если вам действительно не нужно выполнять специальные целочисленные операции над значением указателя (например, инвертировать некоторые биты или что-то вроде этого), как подсказывают ответы на этот вопрос .

0 голосов
/ 17 марта 2020

Измените это:

uintptr_t bufferPtr = (uintptr_t)buffer;

на это:

char *bufferPtr = buffer;

Удалите (uintptr_t) везде в вашей программе.

Я не знаю, почему вы решили использовать uintptr_t, но вам это не нужно.

...