【问题标题】:Different pointer types for the same address相同地址的不同指针类型
【发布时间】:2014-11-18 13:48:38
【问题描述】:

我对编程比较陌生,所以如果我的问题是基本的,我深表歉意。

情况:

我有几个浮点值和一个指向每个值的指针数组。例如:

float nr1=1.15;
float nr2=2.30; 
float nr3=23.34; 

....

float * my_address_array[3]; 

my_address_array[0] = &nr1;
my_address_array[1] = &nr2;
my_address_array[2] = &nr3;

要访问一个元素,我可以使用:

float temp_value; 
float ** ptr_value; 

...

ptr_value = &my_address_array[0];

temp_value = **( ptr_value+0); // copy nr1 to temp
temp_value = **( ptr_value+1); // copy nr2 to temp
temp_value = **( ptr_value+2); // copy nr3 to temp 

到目前为止一切顺利。在我的系统中,浮点数占用 32 位(8051 微控制器)。我需要取一个浮点数并将其分成四个 8 位变量。 nr2 示例:

我的尝试是:

unsigned char storage1; 
unsigned char storage2; 
unsigned char storage3; 
unsigned char storage4; 

...

storage1 =(unsigned char) ((**( ptr_value+1)) >> 24) ;
storage2 =(unsigned char) ((**( ptr_value+1)) >> 16) ;
storage3 =(unsigned char) ((**( ptr_value+1)) >> 8) ;
storage4 =(unsigned char) ((**( ptr_value+1)) & 0xff) ;

我得到错误的操作数类型。似乎我不能对浮点数使用位移操作(至少谷歌是这样的)。我可以添加一个新指针,如:

char ** ptr_char_value; 

...

ptr_char_value = &my_address_array[0];   // generates warning

storage1 = (*(*( ptr_char_value+1)+0));
storage2 = (*(*( ptr_char_value+1)+1));
storage3 = (*(*( ptr_char_value+1)+2));
storage4 = (*(*( ptr_char_value+1)+3));

我确实收到了一个警告(这是公平的),我正在使用 char 类型指针作为浮点值。我也不确定这有多可靠。任何人都可以提出更好的解决方案吗?

谢谢!

编辑:代码适用于 8051 微控制器。我想让它尽可能快/最优。

【问题讨论】:

  • ptr_char_value = &my_address_array[0]; 确实很危险。案例:ptr_char_value 上的指针算术运算。你的目标是什么?
  • 在C中,char类型给所有类型起别名,所以没关系。
  • 有问题的微控制器来自 Silabs C8051F96x (8 bit)
  • 你应该减少那个指针的废话。 **( ptr_value+0) 可以写成*ptr_value[0]。另外,使用更多的临时变量;在多行上重复相同的指针计算是丑陋且不必要的。
  • 我同意数组访问看起来比指针访问更好。但是指针访问速度更快(经过测试)。由于我可能需要执行数百次操作,因此我的性能会受到影响。这可能是编译器优化的事情,但我更喜欢使用指针而不是花时间优化数组访问(然后更改一大块代码)。关于更多临时值,代码看起来与我发布的不同。我只是举个例子来说明问题。

标签: c embedded 8051


【解决方案1】:

有了这个,你得到了指向值的指针

ptr_char_value = &my_address_array[0];

我不明白这应该如何工作。


直接使用指针浮动会更好。将其转换为 char 数组并获取单独的字节。

char * ptr_char_value = (char *)(my_address_array[0]);
storage1 = ptr_char_value[0];
storage2 = ptr_char_value[1];
storage3 = ptr_char_value[2];
storage4 = ptr_char_value[3];

编辑: 如果您真的需要指向浮点数的指针数组,这也是一个问题。可以有 struct,将其转换为字节数组,然后直接将这些字节用于某些事情。

struct my_data_type {
    float nr1;
    float nr2;
    float nr3;
}

struct my_data_type my_data;

my_data.nr1 = 1.15;
my_data.nr2 = 4.75;
my_data.nr3 = 8.95;

char * ptr_char_value = (char *)&my_data;

// nr1
storage1 = ptr_char_value[0];
...

// nr2
storage5 = ptr_char_value[4];
...

// nr3
storage9 = ptr_char_value[8];
...

【讨论】:

  • 如果我正确理解了这个问题,这是最好的方法,您只需要注意字节顺序问题 - ptr_char_value[0] 是否包含最高有效字节或最低有效字节?
【解决方案2】:

试试这个。您应该在移动数据之前键入 cast。包括 stdint.h

      storage1 = (uint8_t) ((((uint32_t)**( ptr_value+1))) >> 24) & 0xFF );

【讨论】:

  • 不。未定义的行为,不允许通过uint32_t * 访问float
  • @EOF 你是对的,但是在 8051 平台上你不能遇到对齐问题
  • @jeb:这是 C 语言,还是某种只在奇怪而奇妙的架构/平台上支持的非标准 C 语言?
【解决方案3】:

让我们从标题开始:

同一地址的不同指针类型

那是代码的味道。在 C 中,通过不兼容的指针类型对对象进行别名会导致未定义的行为,除非不兼容的别名类型是(合格或不合格、有符号或无符号)字符类型。

更准确地说,类型为 cv 限定或非限定 T 的对象只能通过指向限定或非限定 T 的指针来访问。此外,如果T 是一个整数类型,则也允许通过其(合格或不合格)有符号或无符号对应物进行访问。

这就是俗称的“严格别名规则”。

因此,你不能这样做

float f;
*(int *)&f

即使sizeof(float) == sizeof(int).

可能的解决方案:

  1. 使用memcpy(),像这样(首选):
float f = 3.14;
int i;
memcpy(&i, &f, sizeof f);
  1. 使用联合(仅限 C99 - 这也是 C89 中的 UB……):
union {
    float f;
    int i;
} pun = { .f = 3.14 };
printf("%d\n", pun.i);

【讨论】:

  • @EOF 您的第一点是有效的,但是对于第二个 N1570 6.5.2.3,注释 95 说:“如果用于读取联合对象内容的成员与成员最后用于在对象中存储值时,该值的对象表示的适当部分被重新解释为新类型中的对象表示,如 6.2.6 中所述(有时称为“类型双关”的过程)。这可能是一个陷阱表示。”
  • @user694733 你引用的部分说这会产生未定义的行为。
  • @2501 它可以,但不一定。标准基本上说:“这不是 UB,但有一些风险你应该知道。”
  • @2501 这里有一个明确的区别。只要程序员确保避免可能的陷阱表示,就允许在联合上使用双关语。
  • @EOF 实现定义的行为与未定义的行为不同。如果您不知道自己在说什么,请不要有充分的理由投反对票。
【解决方案4】:

为什么要在 4 个变量中分隔浮点数? 这没有任何意义,因为 float 在计算机中是如何表示的。

第一位 S 是 sing,0 表示正数 1 表示负数。然后是 8 位指数,剩下 23 位作为尾数。 所以,你不能用 8bit 部分做任何有用的事情,因为它们本身没有意义。

【讨论】:

  • 它可能只是用于存储到一些内存中,它不打算直接使用,所以在某些情况下它是有意义的
猜你喜欢
  • 1970-01-01
  • 2016-10-06
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-07
  • 2020-02-11
  • 2022-12-09
相关资源
最近更新 更多