【问题标题】:In C, How does one set the value at one address to the value at another address?在 C 中,如何将一个地址的值设置为另一个地址的值?
【发布时间】:2020-03-17 06:21:03
【问题描述】:

我正在尝试制作一些 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 似乎不可取消引用。我收到以下错误:

一元'*'的无效类型参数(有'uintptr_t {aka unsigned int}')

我在网上看过,所有消息来源都告诉我,我必须将uintptr_t 转换回内存地址指向的本机数据类型的指针。我不确定该怎么做,因为使用类型转换(char *),表明缓冲区指针是字符指针无法编译,给我与上面相同的错误。

现在,当我将行更改为 \*(char\*)bufferPtr = \*c; 时,兔子洞会更深一层,这不会给我任何错误。这条线是什么意思?

我希望这意味着将bufferPtr类型转换为char指针的地址处的值设置为c地址处的值。这是正确的吗?

【问题讨论】:

  • uintptr_t 是“unsigned int”,所以你必须把它转换成指针
  • @NoumanTajik 在微控制器代码中,我认为它有点不同,尤其是在 8 位微控制器中,但我明白你在说什么
  • 无论是 PC 还是 MCU,编译器都必须知道您指的是内存位置还是值。你上面所说的错误说同样的事情,即一元'*'的无效类型参数(有'uintptr_t {aka unsigned int}')。我认为 uintptr_t 命名有些混乱,它应该是 typedef 为 (unsigned int *) 而不是 (unsigned int)。
  • @NoumanTajik 那么它们是完全相同的数据类型吗?
  • "uintptr_t" 在你的代码中意味着 (unsigned int) NOT (unsigned int *)

标签: c pointers microcontroller avr


【解决方案1】:

由于bufferPtruintptr_t,它是一个整数类型,而不是指针类型,您必须在取消引用之前将其转换回指针类型。

*(char *)bufferPtr = *c;

这很好,因为bufferPtr 的值的来源来自char 数组。

char buffer[UART_BUF_LEN];
uintptr_t bufferPtr = (uintptr_t)buffer;

【讨论】:

  • 等等,所以你是在告诉我,我复杂的逻辑实际上可能是对的?!很高兴知道我还在学习。
【解决方案2】:

改变这个:

uintptr_t bufferPtr = (uintptr_t)buffer;

到这里:

char *bufferPtr = buffer;

删除程序中所有位置的(uintptr_t)

我不知道你为什么决定使用uintptr_t,但你不需要它。

【讨论】:

  • @tuskiomi 所以?你所有的算术都在char*上运行。
【解决方案3】:

uintptr_t 是一个 integer 类型,用于安全地将指针的值存储在整数中。由于不同的机器和架构具有不同的指针大小,这种类型允许将指针转换为整数类型,而不必担心根据机器选择正确的整数大小(例如 32 位或 64 位整数)。这使得编写可移植代码更容易。

uintptr_t 不是指针类型。这意味着您不能取消引用它,就像您不能取消引用 int 一样。为了能够将其用作指针,您必须将其转换回指针。

char* char_ptr = (char*)bufferptr;
*char_ptr =  *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);

在此示例中,p1p2 将具有完全相同的值。 p0 + 42 会将char 的大小加到p0 中包含的地址的42 倍,但由于char 的大小始终为1,这与第二个版本完全相同。

对于大小不是 1 的类型,结果会有所不同(例如,如果 p0int*float*)。但是,如果您想对指针值进行简单的整数计算(例如,添加或减去偏移量),我仍然建议转换为 char* 而不是 intptr_t,除非您确实需要对指针的值进行专门的整数运算(例如反转一些位或类似的东西),正如the answers to this question 所建议的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多