我不确定C/C++三元运算符的执行保证.
例如,如果给出一个地址和一个布尔值来告诉该地址是否适合阅读,我可以使用if/else轻松避免错误读取:
int foo(const bool addressGood, const int* ptr) {
if (addressGood) { return ptr[0]; }
else { return 0; }
}
Run Code Online (Sandbox Code Playgroud)
但是?:
,ptr
除非addressGood
是真的,否则三元运算符()可以保证不会被访问?
或者优化编译器是否可以生成ptr
在任何情况下访问的代码(可能使程序崩溃),将值存储在中间寄存器中并使用条件赋值来实现三元运算符?
int foo(const bool addressGood, const int* ptr) {
// Not sure about ptr access conditions here.
return (addressGood) ? ptr[0] : 0;
}
Run Code Online (Sandbox Code Playgroud)
谢谢.
我面临着关于C++严格别名规则及其可能含义的困惑.请考虑以下代码:
int main() {
int32_t a = 5;
float* f = (float*)(&a);
*f = 1.0f;
int32_t b = a; // Probably not well-defined?
float g = *f; // What about this?
}
Run Code Online (Sandbox Code Playgroud)
看看C++规范,3.10.10节,从技术上讲,没有一个给定的代码似乎违反了给定的"别名规则":
如果程序试图通过以下类型之一以外的左值访问对象的存储值,则行为未定义:
...合格的访问者类型列表...
*f = 1.0f;
不会违反规则,因为无法访问存储的值,即我只是通过指针写入内存.我不是从记忆中读书或试图在这里解释一个值.int32_t b = a;
不违反规则,因为我通过其原始类型进行访问.float g = *f;
出于同样的原因,这条线并没有违反规则.在另一个线程中,成员CortAmmon实际上在响应中提出了相同的点,并且添加了通过写入活动对象而产生的任何可能的未定义行为,如 *f = 1.0f;
将在标准的"对象生存期"定义(似乎是对于POD类型来说是微不足道的).
但是:互联网上有大量证据表明上述代码将在现代编译器上产生UB.例如,见这里和这里.
在大多数情况下,论证是编译器可以自由考虑&a
,f
而不是相互混叠,因此可以自由重新安排指令.
现在最大的问题是,如果这种编译器行为实际上是对标准的"过度解释".
唯一一次标准谈论"混叠"的唯一一次是在3.10.10的脚注中,其中明确指出那些是控制混叠的规则.
正如我之前提到的,我没有看到任何上述代码违反了标准,但是很多人(可能还有编译人员)认为它是非法的.
我真的很感激这里的一些澄清.
小更新:
正如成员BenVoigt指出的那样,int32_t …
c++ memory compiler-construction strict-aliasing type-punning
这可能会导致未定义的行为吗?
uint8_t storage[4];
// We assume storage is properly aligned here.
int32_t* intPtr = new((void*)storage) int32_t(4);
// I know this is ok:
int32_t value1 = *intPtr;
*intPtr = 5;
// But can one of the following cause UB?
int32_t value2 = reinterpret_cast<int32_t*>(storage)[0];
reinterpret_cast<int32_t*>(storage)[0] = 5;
Run Code Online (Sandbox Code Playgroud)
char
有严格别名的特殊规则.如果我使用char
而不是 uint8_t
它仍然是未定义的行为?还有什么变化?
正如成员DeadMG指出的那样,reinterpret_cast
依赖于实现.如果我改用C风格的演员(int32_t*)storage
,会有什么变化?
c++ strict-aliasing placement-new language-lawyer type-punning
我正在尝试使用OpenGL ES 2.0做一些GPGPU.
在我看来,GL_NV_draw_buffers和GL_OES_texture_float扩展是这里的一些基本要素.
这个问题与GL_OES_texture_float扩展有关:从桌面世界来看,如果格式是固定点(如GL_RGBA),我习惯在着色器中访问纹理时在[0..1]范围内.
咨询相应的OES扩展页面,它说:
"......如果纹理的内部格式是定点的,则组件被限制为[0..1].否则,不会修改值."
现在我已经多次在网上听到过(例如答案:OpenGL GLSL采样器总是返回从0.0到1.0的浮点数),ES 2.0也支持访问片段着色器中未展开的值.但是这个功能在哪里指定?扩展说"否则,值不会被修改",但由于OpenGL ES规范只知道定点格式,因此对我来说没有意义.
另外,据我所知,扩展只指定浮点值可以从客户端内存读取到纹理中,但不指定纹理在图形内存中的表示方式(即每个通道有多少位).这有什么官方规格吗?
最后,我想在我的片段着色器中将未展开的浮点值写入FBO颜色附件,最好每个通道使用32位.这可能吗?
我正在努力实现共享内存缓冲区而不破坏C99的严格别名规则.
假设我有一些处理一些数据的代码,需要有一些'临时'内存来运行.我可以把它写成:
void foo(... some arguments here ...) {
int* scratchMem = new int[1000]; // Allocate.
// Do stuff...
delete[] scratchMem; // Free.
}
Run Code Online (Sandbox Code Playgroud)
然后我有另一个功能,做一些其他需要一个临时缓冲区的东西:
void bar(...arguments...) {
float* scratchMem = new float[1000]; // Allocate.
// Do other stuff...
delete[] scratchMem; // Free.
}
Run Code Online (Sandbox Code Playgroud)
问题是在操作期间可能会多次调用foo()和bar(),并且在性能和内存碎片方面,整个地方的堆分配可能非常糟糕.一个明显的解决方案是分配一个适当大小的公共共享内存缓冲区,然后将其作为参数传递给foo()和bar(),BYOB样式:
void foo(void* scratchMem);
void bar(void* scratchMem);
int main() {
const int iAmBigEnough = 5000;
int* scratchMem = new int[iAmBigEnough];
foo(scratchMem);
bar(scratchMem);
delete[] scratchMem;
return 0;
}
void foo(void* scratchMem) {
int* smem = (int*)scratchMem;
// …
Run Code Online (Sandbox Code Playgroud) 此问题与OpenGL ES 2.0 Extension EXT_discard_framebuffer有关.
我不清楚哪些案例证明使用此扩展是合理的.如果我调用glDiscardFramebufferEXT()并将指定的可附加图像置于未定义状态,这意味着:
- 我不再关心内容,因为它已经与glReadPixels()一起使用了,
- 我不在乎因为它已经与glCopyTexSubImage()一起使用了,所以内容已经存在,
- 我不应该首先进行渲染.
显然,只有前两种情况有意义,还是其他情况下glDiscardFramebufferEXT()是有用的?如果是,这些情况是哪些?
我正在尝试编写自己的委托系统作为boost :: functions的替代,因为后者执行了大量的堆分配,我认为这些分配是有问题的.
我已将此作为替换(简化,实际使用池内存和放置新的但这很简单,可以重现错误):
template<class A, class B>
struct DelegateFunctor : public MyFunctor {
DelegateFunctor(void (*fptr)(A, B), A arg1, B arg2) : fp(fptr), a1(arg1), a2(arg2) {}
virtual void operator()() { fp(a1, a2); }
void (*fp)(A, B); // Stores the function pointer.
const A a1; const B a2; // Stores the arguments.
};
Run Code Online (Sandbox Code Playgroud)
和这个辅助函数:
template<class A, class B>
MyFunctor* makeFunctor(void (*f)(A,B), A arg1, B arg2) {
return new DelegateFunctor<A,B>(f, arg1, arg2);
}
Run Code Online (Sandbox Code Playgroud)
奇怪的事情发生在这里:
void bar1(int a, int b) {
// do …
Run Code Online (Sandbox Code Playgroud) 这基于以下问题:在OpenGL着色器中检测NaN的最佳方法
标准GLSL定义用于检测的isnan()和isinf()函数.OpenGL ES 2.0着色语言没有.我怎么能处理NaN和Infs呢?