【问题标题】:Passing Variable To Function Changes Address Location in C将变量传递给函数会更改 C 中的地址位置
【发布时间】:2018-06-27 21:03:30
【问题描述】:

在将参数传递给函数时遇到了一个奇怪的问题。

参数是一个结构体,定义为:

#pragma pack(push,1)
 typedef struct {
     struct {
         uint8_t opcode;
         uint8_t type;
         union {
             uint8_t attr;
             struct {
                 unsigned int reserved : 6;
                 unsigned int sequence : 2;
             };
         };
         uint8_t bytes;
     } header;
     uint8_t payload[15];
 } message_t;
 #pragma pack(pop)

我有一个函数将这个结构声明为:

void func1(void) {
    message_t response;

在这个函数中,我将它作为参数传递给另一个函数:

    func2(response);

func2 内我声明了另一个结构体,它被定义为:

 #pragma pack(push,1)
 typedef struct {
     struct {
         uint8_t op_code;
         avneraIDs_t IDs;
         uint8_t length;
     } header;
     uint8_t payload[30];
 } frame_t;
 #pragma pack(pop)

此结构在func2 中声明为:

frame_t frame;

所以现在我在func2 打电话给memcpy

memcpy((uint8_t *)&response, frame.payload, (frame.header.length - 1));

我已经验证frame.header.length 等于 20,现在减 1 将复制超过 19 个字节的数据。 response 的宽度为 19 个字节,所以应该没问题。

执行memcpy后,我打印出response的内容,内容看起来是正确的。

返回func1后我再次打印response的内容。现在内容没了,又是空的。

所以我做的调试是在func1 的上下文中打印response 的地址位置,然后得到地址0x2000a470

如果我在func2 的上下文中打印response 的地址位置,我会得到地址0x2000a484

如果我打印从地址0x2000a484 开始的内存,我会看到应该在response 中的数据。

为什么response 的地址在我将它传递给另一个函数后立即更改?

还有一些额外的信息,我正在用 C 语言编写,使用 GCC 和 ST Arm Core MCU。

【问题讨论】:

  • 我觉得这个代码太拼了,你能不能试试更连贯的minimal reproducible example
  • response 按值传递给func2..
  • 注意:不要期望union { uint8_t attr; struct { unsigned int reserved : 6; unsigned int sequence : 2; }; }; 以可移植的方式覆盖uint8_t 和位字段。
  • "返回 func1 后......" - 这本身就说明了问题,没有看代码就无法确定。鉴于您使用response 的方式,该代码有希望工作的唯一方法是它是否是全局代码。您的代码中并非如此。您正在使用func2(response);,这意味着您将其按值提供给func2。调用者的参数将保持不变。通过地址将其传递给func2 更改它以接受指针作为其形式参数。最后,将func2 中的&response 用法更改为简单的response,因为它已经是一个正确的指针了。
  • 为了简化@WhozCraig 所说的,func2() 中的变量response 是来自func1() 的变量的副本。您对副本所做的更改不会影响原件。需要传递一个指针,才能得到引用传递的效果。

标签: c arguments parameter-passing memory-address memcpy


【解决方案1】:

您正在 func1func2 之间传播传递值。你的代码有一个功能,

void func2(message_t response) // <<==== response gets value from caller
{
    memcpy(&response, ....) // <<==== modify local response; caller is unaffected.
}

void func1()
{
    message_t respnose;
    func2(response); // <<==== PASSED BY VALUE
}

C 是按值传递的,您需要制作该值以允许您想要的修改:

void func2(message_t *response) // <<==== receiving address of caller's response
{
    memcpy(response, ...); // <<=== using address of caller's response.
}

void func1()
{
    message_t response;
    func2(&response); // <<==== passing address of our response
}

这应该可以解决您的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 2013-05-05
    • 2020-01-09
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多