This question询问是否可以依赖编译器来处理<button data-ng-disabled="!form.valid && !uploaded">Submit</button>
s值顺序和填充。
根据该问题的答案,
OpenGL非常清楚地定义了
struct
接口块的字节布局。C ++ 11定义了一个名为"standard layout types"的概念。
C ++告诉你关于布局的标准布局类型的唯一事情是忽略空基类(只要它仍然是标准布局),并且第一个NSDM将在类的最开始。也就是说,前面永远不会有填充物。
标准所说的另一件事是,相同访问类的NSDM将按顺序分配,后者的偏移量比之前的偏移量大。
但就C ++标准而言,就是这样。 [class.mem] / 13声明实现可以出于各种原因在成员之间添加填充。
那可能但并不总是存在填充可能真的搞砸了,最糟糕的部分 - 它取决于编译器。
为了避免错误和恶梦,使用与编译器无关的方法是不是更好?
例如:
std140
与天真相反:
class BufferData
{
private:
GLfloat data[12];
public:
GLfloat* getCameraPosition()
{
return (GLfloat*) &data[0];
}
GLfloat* getLightPosition()
{
return (GLfloat*) &data[4];
}
GLfloat* getLightDiffuse()
{
return (GLfloat*) &data[8];
}
GLfloat* getData()
{
return data;
}
};
或者天真的做法是否足够好?
(假设类/结构不仅仅是那个,而且可能会改变)
答案 0 :(得分:1)
“编译器不可知”?没有这样的动物。你试图写一个证明了它。考虑您的结构成员定义:
GLfloat data[12];
这需要存在GLfloat
类型。但问题是,C ++没有定义那种类型。 OpenGL可以。
OpenGL非常清楚地定义了这种类型:它是IEEE-754 floating-point type, using the BINARY32 format。
问题是,C ++不要求float
符合这一点。实际上,C ++并不要求其类型的任何符合这一点。如果编译器希望float
使用IEEE-754之外的其他东西,那就没问题了。
现在,您可以说OpenGL头可以将GLfloat
定义为类型,大小为32位,将从编译器的float
类型转换为IEEE-754。当然,这可能发生......除非没有办法获得32位值。
有些系统有9位字节。或18位字节。这些系统有C ++编译器。此类系统无法声明只有32位大小的类型。
但能够传递32位值(更不用说16位和8位)是OpenGL的硬性要求。没有它,您将无法在缓冲区对象中传递任何数据。然而,C ++并不需要它。
说到顶点数据,半现代OpenGL中最基本的功能之一是glVertexAttribPointer
。并且依赖将一个字节偏移量转换为void*
,然后它将被转回。
C ++不保证这有效。在C ++标准中没有任何地方要求如果你将一个整数转换为指针,然后将该指针强制转换为整数,你将得到相同的整数(它确实说ptr-&gt; int-&gt; ptr工作,但这并不意味着反过来。)
然而OpenGL需要它。除非您使用单独的属性缓冲区(和I strongly suggest you do if it's available),否则您的代码和您调用的OpenGL代码将依赖于此未定义的行为。
OpenGL将GLint
定义为带符号的二进制补码,32位整数。但是C ++不要求任何整数类型是两个补码。
但是OpenGL可以。
OpenGL flat out无法在类型异常的系统上运行。它不能在具有9位字节的系统上运行。它不能在使用有符号整数数学补码的系统上运行。我可以继续这样做,但我认为我的观点很明确。
通过选择使用OpenGL(Vulkan,如果你想知道),你已经依赖于实现定义的行为。那么,当您已经依赖于大量其他实现定义的行为时,为什么还要让您的生活更难以避免这种特定的实现定义行为呢?
这匹马离开了谷仓;现在关门没有帮助。