我有一个公开面向结构A和内部结构B的API,需要能够将结构B转换为结构A.以下代码在C99(和VS 2010/C89)和C中是合法且定义良好的行为 ++ 03/C++ 11?如果是,请解释是什么使它明确定义.如果不是,那么在两种结构之间进行转换的最有效和跨平台的方法是什么?
struct A {
uint32_t x;
uint32_t y;
uint32_t z;
};
struct B {
uint32_t x;
uint32_t y;
uint32_t z;
uint64_t c;
};
union U {
struct A a;
struct B b;
};
int main(int argc, char* argv[]) {
U u;
u.b.x = 1;
u.b.y = 2;
u.b.z = 3;
u.b.c = 64;
/* Is it legal and well defined behavior when accessing the non-write member of a union in this case? */
DoSomething(u.a.x, u.a.y, …Run Code Online (Sandbox Code Playgroud) 我知道标准中明确允许以下内容:
int n = 0;
char *ptr = (char *) &n;
cout << *ptr;
Run Code Online (Sandbox Code Playgroud)
那这个呢?
alignas(int) char storage[sizeof(int)];
int *ptr = (int *) &storage[0];
*ptr = 0;
cout << *ptr;
Run Code Online (Sandbox Code Playgroud)
本质上,我问的是,别名规则是否允许通过指向另一种类型的指针访问一系列字符.我想参考标准的部分,如果可能的话,表明这种或那种方式.
标准的某些部分让我感到矛盾; (3.10.10)似乎表明在假设动态类型storage不是的情况下它将是未定义的行为int.然而,动态类型的定义对我来说并不清楚,而且存在std::aligned_storage会让我相信这是可能的.
我需要在C++中实现非常快速的log2(float x)函数.
我发现了一个非常有趣的实现(非常快!)
#include <intrin.h>
inline unsigned long log2(int x)
{
unsigned long y;
_BitScanReverse(&y, x);
return y;
}
Run Code Online (Sandbox Code Playgroud)
但是此函数仅适用于输入中的整数值.
问题:有没有办法将此函数转换为double类型的输入变量?
UPD:
我找到了这个实现:
typedef unsigned long uint32;
typedef long int32;
static inline int32 ilog2(float x)
{
uint32 ix = (uint32&)x;
uint32 exp = (ix >> 23) & 0xFF;
int32 log2 = int32(exp) - 127;
return log2;
}
Run Code Online (Sandbox Code Playgroud)
这比前一个示例快得多,但输出是无符号类型.
是否可以使此函数返回double类型?
提前致谢!
C++ 的联合比 C 的联合更具限制性,因为它们引入了“活动成员”(最后分配的成员)的概念,作为唯一可以安全访问的成员。在我看来,工会的这种行为完全是负面的。有人可以解释一下这种限制会带来什么好处吗?
以下是现代C中未定义的行为:
union foo
{
int i;
float f;
};
union foo bar;
bar.f = 1.0f;
printf("%08x\n", bar.i);
Run Code Online (Sandbox Code Playgroud)
并打印1.0f的十六进制表示.
但是以下是未定义的行为:
int x;
printf("%08x\n", x);
Run Code Online (Sandbox Code Playgroud)
那这个呢?
union xyzzy
{
char c;
int i;
};
union xyzzy plugh;
Run Code Online (Sandbox Code Playgroud)
这应该是未定义的行为,因为没有plugh编写成员.
printf("%08x\n", plugh.i);
Run Code Online (Sandbox Code Playgroud)
但是这个呢.这是未定义的行为吗?
plugh.c = 'A';
printf("%08x\n", plugh.i);
Run Code Online (Sandbox Code Playgroud)
现在大多数C编译器都有sizeof(char) < sizeof(int),sizeof(int)或者是2或4.这意味着在这些情况下,最多plugh.i会写入50%或25%,但读取剩余的字节将读取未初始化的数据,因此应该是未定义的行为.在此基础上,是整个读取未定义的行为?
我们有特殊的函数,比如std::nanl用有效负载创建 NaN。目前,我需要执行以下操作才能将其打印回来:
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdint>
int main()
{
const auto x=std::nanl("1311768467463790325");
std::uint64_t y;
std::memcpy(&y,&x,sizeof y);
std::cout << (y&~(3ull<<62)) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
这依赖于 的特定表示long double,即它是 x87 FPU 的 80 位类型。是否有任何标准方法可以在不依赖此类实施细节的情况下实现这一目标?
我最近发现了vreinterpret {q} _dsttype_srctype转换运算符.但是,这似乎不支持此链接(页面底部)中描述的数据类型的转换:
一些内在函数使用以下形式的向量类型数组:
<type><size>x<number of lanes>x<length of array>_t这些类型被视为包含名为val的单个元素的普通C结构.
示例结构定义是:
Run Code Online (Sandbox Code Playgroud)struct int16x4x2_t { int16x4_t val[2]; };
你知道如何转换uint8x16_t成uint8x8x2_t?
请注意,使用union无法可靠地解决问题(从非活动成员读取导致未定义的行为编辑:这只是C++的情况,而事实证明C允许类型惩罚),也没有使用指针来强制转换(打破严格别名规则).
我已经在 Stack Overflow 上搜索了答案,但我没有得到任何特定于这个问题的信息:只有关于使用各种类型转换运算符的一般情况。因此,恰当的情况是使用 Windows GetProcAddress()API 调用检索函数地址时,该调用返回类型为 的函数指针FARPROC,其中:typedef INT_PTR (__stdcall *FARPROC)();。
问题是,所寻求的实际函数很少(如果有的话)具有这个实际签名,如下面的 MRCE 代码所示。在这段代码中,我展示了将返回值转换为适当类型的函数指针的各种不同尝试,除了第四种方法之外的所有方法都被注释掉了:
#include <Windows.h>
#include <iostream>
typedef DPI_AWARENESS_CONTEXT(__stdcall* TYPE_SetDPI)(DPI_AWARENESS_CONTEXT); // Function pointer typedef
static DPI_AWARENESS_CONTEXT __stdcall STUB_SetDpi(DPI_AWARENESS_CONTEXT) { return nullptr; } // Dummy 'stub' function
static DPI_AWARENESS_CONTEXT(__stdcall* REAL_SetDpi)(DPI_AWARENESS_CONTEXT) = STUB_SetDpi; // Func ptr to be assigned
using std::cout; using std::endl;
int main()
{
HINSTANCE hDll = LoadLibrary("User32.dll");
if (!hDll) {
cout << "User32.dll failed to load!\n" << endl;
return 1;
}
cout << …Run Code Online (Sandbox Code Playgroud) 让我们立即开始示例代码:
#include <stdio.h>
#include <stdbool.h>
typedef union {
bool b;
int i;
} boolIntUnion;
int main(void) {
boolIntUnion val;
val.i = 0;
printf("i = %d; %s\n", val.i, ((val.b) ? "true" : "false"));
val.i = 1;
printf("i = %d; %s\n", val.i, ((val.b) ? "true" : "false"));
val.i = 2;
printf("i = %d; %s\n", val.i, ((val.b) ? "true" : "false"));
}
Run Code Online (Sandbox Code Playgroud)
我现在的问题是,如果使用您在这里看到的联合是某种未定义的行为。我感兴趣的是第三种情况,我将其设置val.i为2,但随后使用 union via 中的布尔值val.b作为打印字符串的条件。2在 MSVC 19 和 gcc 中,我得到了联合中的预期行为,导致了truefrom的值val.b,但是使用 …
考虑下面的代码。我们知道一个__uint128_t变量存储在 2 个 64 位寄存器中(假设 x64 处理器)。要求是将前 64 位存储在一个 unsigned long 变量中,并将接下来的 64 位存储在另一个 unsigned long 变量中。
__uint128_t a = SOMEVALUE;
unsigned long b = a&0xffffffffffffffff;
unsigned long c = a>>64;
Run Code Online (Sandbox Code Playgroud)
这里,b存储前 64 位,c存储接下来的 64 位。有没有其他更简单的方法来分别访问两个寄存器而不是执行&和>>操作?我问这个问题是因为对于我的项目,这部分代码将被执行一万亿次以上。所以这个疑问还是先验证一下比较好。
有什么汇编代码可以让我闲逛吗?