登录 立即注册

找到2246个回复 (用户: 老虎会游泳)

老虎会游泳 64楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

https://blog.csdn.net/xkdlzy/article/details/108873014

小于等于64位的整型或指针类型返回值由RAX传递。
浮点返回值由XMM0传递。
更大的返回值(比如结构体),由调用方在栈上分配空间,并有RCX持有该空间的指针并传递给被调用函数,因此整型参数使用的寄存器依次右移一格,实际只可以利用3个寄存器,其余参数入栈。函数调用结束后,RAX返回该空间的指针。

但函数没有返回值(void),所以不清楚上面的案例中RCX用于什么,x64调用约定没有明说。

老虎会游泳 63楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,上面的代码:

因为target是struct T的第一个成员,所以它的首地址就是this。也就是说,this在rdx寄存器。

x64调用约定

整数参数在寄存器 RCX、RDX、R8 和 R9 中传递。

所以this既然在RDX中,那么它应该是第二个整数参数,第一个可能是返回地址。

老虎会游泳 61楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,对了,VC++的__thiscall调用约定始终将this指针放在ecx寄存器。

https://learn.microsoft.com/zh-cn/cpp/cpp/thiscall?view=msvc-170

__thiscall 的调用约定用于 x86 体系结构上的 C++ 类成员函数。 它是成员函数使用的默认调用约定。

在 __thiscall 下,被调用方清理堆栈,自变量将从右到左推送到堆栈中。 指针 this 通过寄存器 ECX 传递,而不是在堆栈上传递。

老虎会游泳 60楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊this可能已经优化到了寄存器中。

T::unpack3bit 每次移位之前都重新获取 target 变量的地址放到 rdi 中, mov rdi, QWORD PTR [rdx] ,而 target 整个过程没有改变,这样做没有必要。

这里是在读取target指针的值,mov rdi, QWORD PTR [rdx],是以rdx寄存器的值为内存首地址,连续读取8字节到rdi寄存器。

因为targetstruct T的第一个成员,所以它的首地址就是this。也就是说,thisrdx寄存器。

所以问题是程序一直在从内存加载this->target,而非一直在从内存加载this

老虎会游泳 59楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)
int a, b, c, d, e, f, g;
int *h = &b;

而在这种情况下,可能是a、c、d、e、h在寄存器,b在内存,因为&b需要一个内存地址。指针h通常在寄存器,因为这样更快。至于a、c、d、e、f、g哪个在寄存器哪个在内存,取决于它们的使用情况。

老虎会游泳 57楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,举个例子:

int a, b, c, d, e, f, g;

如果有5个空闲寄存器,那么a到e就只在寄存器,完全不在内存,f和g在内存,根据需要读取到寄存器。

既然可以完全优化至寄存器,自然不需要考虑缓存失效问题。

而指向缓冲区的局部指针变量恰好符合完全优化至寄存器的条件。

老虎会游泳 56楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊this是一个内存地址,既然是内存地址,所以当然在内存。编译器的问题只是在没有必要的情况下反复读取了它。

而我说的寄存器变量,是完全不在内存,在且仅在寄存器的变量,这样的变量根本没有内存地址。

老虎会游泳 54楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,寄存器没有内存地址,所以任何有地址的内容必然在内存,但是在内存不意味着慢,因为它还可以同时存在于L3/L2/L1缓存中,而且也不必马上写回内存。

任何不需要有内存地址的内容,都可以放进寄存器,只要寄存器还没满。

内容在不在寄存器是静态分配的,编译的时候就决定了,查看汇编代码就能看出来。

如果寄存器还没满,并且内容不需要有内存地址,编译器没有理由不把它放进寄存器,除非专门指示它不进行此类优化(-O0volatile)。

老虎会游泳 52楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,以下是可能的分配:

char buf[16]; // 数组只能在内存,因为数组访问操作涉及取地址。内存中的数据会自动逐级缓存在L3/L2/L1 Cache,该操作由CPU自动完成。
char *read_next = buf; // 指针本身可以在寄存器,指向的内容当然不在寄存器,只可能在内存和缓存中
char *write_next = buf + 16; // 指针本身可以在寄存器,指向的内容当然不在寄存器,只可能在内存和缓存中

如果一个内容可以被指针指向,意味着它一定有一个内存地址,也就是说它一定在内存中,当然它也可以同时在L3/L2/L1 Cache中,但不会在寄存器中。在寄存器中的内容没有内存地址。

但是指针本身(也就是内存地址这个数值本身)可以在寄存器中。

老虎会游泳 50楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊

缓存至寄存器

没有这种操作。

一个变量要么在寄存器,要么在内存,不会同时位于两者。

位于内存的变量只会被缓存到L3/L2/L1 Cache中,不会位于寄存器。而这个缓存操作是CPU自动进行的,不需要程序控制。

所以,变量在不在寄存器,看汇编代码就能知道,不需要运行时确定。

老虎会游泳 48楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,至于43楼的设计到底能不能认为所有权发生了转移,我认为是值得争议的问题。

因为从瞬时来看,每个单独的时刻,所有权都从读指针转移到了写指针。

但从全局来看,所有权在读指针和写指针之间共享。

所以到底算不算转移,可能是“实现定义的”

老虎会游泳 46楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊restrict针对的是指针指向的内容,不是指针本身。指针本身是否被优化到寄存器与restrict无关。如果不对指针进行取地址操作,它就可以被优化到寄存器。如果不确定,你可以用gcc -O2 -S查看汇编代码。

老虎会游泳 44楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,我知道你想采用的方法。我的观点是如果不确定就不要使用。

注解
restrict 限定符(像寄存器存储类)是有意使用以促进优化的。而从所有组成一致程序的预处理翻译单元中,删除所有此限定符的实例不会影响其含义(即可观的行为)。
编译器可以忽略任何一个或全部使用 restrict 的别名使用暗示。
欲避免未定义行为,程序员应该确保 restrict 限定指针所做的别名引用断言不会违规。

此外实现类型转换解引用的另一个方案:

许多编译器提供作为 restrict 对立面的语言扩展:指示即使指针类型不同,也可以别名使用的属性: may_alias (gcc)

老虎会游泳 42楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,有一个实验方法,就是用 gcc -O2 -S 编译一段函数,看看加restrict和不加有什么区别。

老虎会游泳 41楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,至于性能问题,据我所知编译器很少生成主动刷新CPU缓存的代码,大部分工作都是交由CPU自动完成的,除非涉及同步原语(信号量、互斥锁等)。

老虎会游泳 40楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,如果问题是阅读理解,我会回答“不行”。

若某个可由 P (直接或间接)访问的对象会被任何手段修改,则该块中所有对该对象(读或写)的访问,都必须经由 P 出现,否则行为未定义。

之前读和之后读都是读。文段中没有体现出时间前后的区别,只强调了定义域的区别。如果读访问发生在不含指针P的块中,则不会有问题。

老虎会游泳 35楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,根据以下文段,我觉得所有权的转移是在声明时发生的,而非使用时发生的。所以只要这个定义域内存在“restrict 指针 P”,就不能通过其他手段访问。

在每个声明了 restrict 指针 P 的块(典型例子是函数体的执行,其中 P 为参数)中,若某个可由 P (直接或间接)访问的对象会被任何手段修改,则该块中所有对该对象(读或写)的访问,都必须经由 P 出现,否则行为未定义。

只有一种情况可以存在其他别名:“restrict 指针 P”指向的内容不会进行任何修改。

若对象决不被修改,则它可以被别名引用,并被异于 restrict 限定的指针访问。

老虎会游泳 33楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,对,restrict的作用应该是所有权的转移,规则应该和Rust类似:所有权转移给某别名之后,就不能再用其他别名访问了,但是转移之前则可以。

老虎会游泳 31楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,顺便一提,在安卓上long是64位,这就是符号位差异的来源

Screenshot_20230127_170107.jpg(97.4 KB)

还有,memcpy看起来是最佳选择,因为它没有任何多余的操作——我们想要的就是内存复制,所以我们就应该写内存复制。改成memcpy后,代码比用联合与指针类型转换都简单。

#include <stdio.h>
#include <stdint.h>                                                                                     float Q_rsqrt( float number ) {
  int32_t i = 0;
  const float threehalfs = 1.5F;

  float x2 = number * 0.5F;
  float y  = number;
  memcpy(&i, &y, sizeof(y));                       // evil floating point bit level hacking
  i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
  memcpy(&y, &i, sizeof(y));
  y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

  return y;
}

int main() {
  printf("sizeof(long):    %lu\n", sizeof(long));
  printf("sizeof(int32_t): %lu\n", sizeof(int32_t));
  printf("sizeof(float):   %lu\n", sizeof(float));

  printf("%0.7f\n", Q_rsqrt(3.14));
  printf("%0.7f\n", Q_rsqrt(1024.0));
  printf("%0.7f\n", Q_rsqrt(10086.0));
  printf("%0.7f\n", Q_rsqrt(2147483647.0));

  printf("%0.14f\n", Q_rsqrt(3.14));
  printf("%0.14f\n", Q_rsqrt(1024.0));
  printf("%0.14f\n", Q_rsqrt(10086.0));
  printf("%0.14f\n", Q_rsqrt(2147483647.0));

  return 0;
}
老虎会游泳 29楼回复 无名啊如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢? (2023-01-27//)

@无名啊,你说得对,( long * ) &y是左值,* ( long * ) &y是对它求值。

不过Q_rsqrt()改写成符合标准似乎很容易。

还有符号位的处理与union版本存在差异,所以确实可能涉及未定义行为。得到负数解可能才是这种内存操作应该有的结果。

下一页 上一页 (43 / 113页)

3月3日 11:41 星期二

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1