我在想:
如果我有结构定义,例如,像这样:
struct Base {
int foo;
};
struct Derived {
int foo; // int foo is common for both definitions
char *bar;
};
Run Code Online (Sandbox Code Playgroud)
我可以这样做吗?
void foobar(void *ptr) {
((struct Base *)ptr)->foo = 1;
}
struct Derived s;
foobar(&s);
Run Code Online (Sandbox Code Playgroud)
例如,当它的类型实际上时,将void指针强制转换Base *为访问它?fooDerived *
在C中翻转双(或浮点)符号的最快方法是什么?
我想,直接访问符号位将是最快的方法,并找到以下内容:
double a = 5.0;
*(__int64*)&a |= 0x8000000000000000;
// a = -5.0
float b = 3.0;
*(int*)&b |= 0x80000000;
// b = -3.0
Run Code Online (Sandbox Code Playgroud)
但是,上述内容不适用于负数:
double a = -5.0;
*(__int64*)&a |= 0x8000000000000000;
// a = -5.0
Run Code Online (Sandbox Code Playgroud) void compute(int rows, int columns, double *data) {
double (*data2D)[columns] = (double (*)[columns]) data;
// do something with data2D
}
int main(void) {
double data[25] = {0};
compute(5, 5, data);
}
Run Code Online (Sandbox Code Playgroud)
有时,将参数视为多维数组非常方便,但需要将其声明为指向平面数组的指针.将指针视为多维数组是否安全,compute如上例所示?我很确定内存布局可以保证正常工作,但我不知道标准是否允许指针以这种方式进行转换.
这会破坏任何严格的别名规则吗?指针算法的规则怎么样; 由于数据"实际上不是"a double[5][5],我们是否允许执行指针算法和索引data2D,或者是否违反了指针算法不会偏离适当数组范围的要求?是data2D即使保证指向正确的地方,还是它只是保证我们可以将它转换回并恢复data?标准报价将非常感激.
根据标准,在C++中始终是未定义的行为,例如,float*指向与a 相同的内存位置int*,然后从它们读/写.
在我的应用程序中,可以有一个填充32位整数元素的缓冲区,它被32位浮点元素覆盖.(它实际上包含一个图像的表示,它由GPU内核在多个阶段进行转换,但是也应该有一个主机实现执行相同的处理,以进行验证.)
该程序基本上这样做(不是实际的源代码):
void* buffer = allocate_buffer(); // properly aligned buffer
static_assert(sizeof(std::int32_t) == sizeof(float), "must have same size");
const std::int32_t* in = reinterpret_cast<const std::int32_t*>(buffer);
float* out = reinterpret_cast<float*>(buffer);
for(int i = 0; i < num_items; ++i)
out[i] = transform(in[i]);
Run Code Online (Sandbox Code Playgroud)
有没有办法reinterpret_cast在C++标准中明确定义指针大小写,而不需要为整个缓冲区做额外的内存副本,或者额外的每个元素副本(例如std::bit_cast)?
我正在用c ++编写一个类,它支持任何类型的变量来帮助我完成未来的项目.问题是,当我尝试为void*变量赋值时,我得到错误:void*不是指向对象的指针类型.这是代码:
int main (void) {
void* a;
int x;
a = malloc(sizeof(int));
x = 120;
((int)(*a)) = x;
printf("%d",((int)*a));
free(a);
system("pause");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我看到它就像我试图在为a保留的内存块中分配x的值.我希望存储在x中的值存储在a的内存块中.可以帮我吗?
我正在阅读ISO/IEC 9899:TC2中第6.5段的第7段.
它通过以下方式宽恕对对象的左值访问:
一种聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),
请参阅文档,了解"前面提到的"类型,但它们肯定包含对象的有效类型.
它的部分标注为:
此列表的目的是指定对象可能或可能没有别名的情况.
我读这是说(例如)以下定义很好:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
unsigned int x;
} s;
int main(void){
unsigned int array[3] = {73,74,75};
s* sp=(s*)&array;
sp->x=80;
printf("%d\n",array[0]);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
该程序应输出80.
我不是在提倡这是一个好的(或非常有用的)想法,并且承认我在某种程度上解释它是因为我无法想到其他意味着什么并且不能相信它是一个毫无意义的句子!
也就是说,我看不出有理由禁止它.我们所知道的是该位置的对齐和内存内容是否兼容,sp->x为什么不呢?
它似乎甚至可以说,如果我double y;在结构的末尾添加(说)a ,我仍然可以array[0]通过sp->x这种方式访问它.
但是,即使数组大于sizeof(s)任何访问尝试sp->y都是'所有下注'未定义的行为.
可能我礼貌地要求人们说出那句话宽恕而不是进入一个扁平的旋转喊"严格混淆UB严格别名UB"似乎经常是这些事情的方式.
第一个类将用于私有继承,以确保完全相同的布局.这应该使铸件安全.
#include <iostream>
#include <string>
struct data_base
{
data_base( int i, std::string&& s ) noexcept
: i_{ i }
, s_{ std::move( s ) }
{}
int i_;
std::string s_;
};
Run Code Online (Sandbox Code Playgroud)
在这个简单的例子,我打印int数据成员第一接着std::string对实例数据成员data<true>.
template<bool = true>
struct data : private data_base // inherits
{
data( int i, std::string&& s ) noexcept
: data_base( i, std::move( s ) )
{}
void print()
{
std::cout << "data<true> - " << i_ << s_ << '\n';
}
}; …Run Code Online (Sandbox Code Playgroud) 在当前的标准草案(和C++ 17)中,这是关于static_casting的void *:
类型"指针的prvalue CV1空隙"可以被转换成类型的prvalue"指针CV2 T",其中T是一个对象类型和CV2是相同的CV-资格,或更大的CV-资格比,CV1.如果原始指针值表示存储器中字节的地址A而A不满足T的对齐要求,则未指定结果指针值.否则,如果原始指针值指向对象a,并且存在类型为T(忽略cv-qualification)的对象b,该对象b是指针可互换的,则结果是指向b的指针.否则,转换指针值不变.
我想知道,转换是指针可互换的有什么区别?有没有一种情况,当一个void *东西指向一个指针 - 可互换实际上改变指针值?这种区别的意图是什么?
对于完整性指针可互换:
如果出现以下情况,则两个对象a和b是指针可互换的:
- (4.1)它们是同一个对象,或者
- (4.2)一个是union对象,另一个是该对象的非静态数据成员([class.union]),或者
- (4.3)一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则该对象的任何基类子对象([class. mem]),或
- (4.4)存在对象c,使得a和c是指针可互换的,并且c和b是指针可互换的.
如果两个对象是指针可互换的,则它们具有相同的地址,并且可以通过reinterpret_cast从指向另一个的指针获得指向一个对象的指针.
最近有人提出这个:
uint8_t a = 0b10000000;
int8_t b = *(int8_t*) &a;
Run Code Online (Sandbox Code Playgroud)
是未定义的行为,因为 的值a超出了我在int8_t. 有人可以解释为什么这是未定义的行为吗?
我的主要问题是内存在那里,并且作为 的内存有效int8_t,唯一的区别是int8_t将该字节解释为-128,而uint8_t将其解释为128。我对此感到更加困惑,因为快速平方根反函数使用:
float y = /* Some val*/;
int32_t i = * ( int32_t * ) &y;
Run Code Online (Sandbox Code Playgroud)
这将给出一个i本质上与 无关的值(除了 IEEE 标准)y,所以我不明白为什么重新解释一段内存可能是未定义的行为。
阅读本文我理解你可以使用别名结构(不违反标准),如果它们具有兼容的成员,即给定以下结构:
typedef struct {
uint32_t a;
uint32_t b;
} Frizzly;
Run Code Online (Sandbox Code Playgroud)
以下将破坏别名规则:
uint32_t foo(uint16_t *i) {
Frizzly *f = (Frizzly *)i;
return f->a;
}
Run Code Online (Sandbox Code Playgroud)
但以下不会:
uint32_t foo(uint32_t *i) {
Frizzly *f = (Frizzly *)i;
return f->b;
}
Run Code Online (Sandbox Code Playgroud)
因为所讨论的"聚合类型"包含与我们投入其中的指针兼容的类型,即指向类型的指针uint32_t可以被转换为包含类型成员(或成员)的结构,uint32_t而不会破坏别名规则.
首先,我是否理解正确?
其次,结构中(其他)变量的排序和类型是否重要?比如说,如果Frizzly定义如下:
typedef struct {
uint16_t b[2];
uint32_t a;
}
Run Code Online (Sandbox Code Playgroud)
在第二个示例中进行强制转换后,b现在由不兼容(uint32_t)类型的内存支持.转换是否仍然有效(或者更确切地说,通过转换指针访问值)?是否会更改任何元素a更改第一个元素的值i(以及相反的方式),就像禁用严格别名一样?
另外,如果以上内容有效,如果我有这样的结构怎么办:
typedef struct {
void *m;
uint16_t hooah[4];
} Bar;
Run Code Online (Sandbox Code Playgroud)
如果我是正确的话,以下演员会破坏别名规则:
void test(char *boo, size_t dee) …Run Code Online (Sandbox Code Playgroud)