NULL + int 的结果是什么? [英] What is the result of NULL + int?

查看:20
本文介绍了NULL + int 的结果是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到在 OpenGL VBO 实现中使用了以下宏:

I have seen the following macro being used in OpenGL VBO implementations:

#define BUFFER_OFFSET(i) ((char *)NULL + (i))
//...
glNormalPointer(GL_FLOAT, 32, BUFFER_OFFSET(x));

您能否详细介绍一下这个宏的工作原理?可以用函数代替吗?更确切地说,增加一个 NULL 指针的结果是什么?

Could you provide a little detail on how this macro works? Can it be replaced with a function? More exactly, what is the result of incrementing a NULL pointer?

推荐答案

让我们回顾 OpenGL 的肮脏历史.曾几何时,有 OpenGL 1.0.您使用 glBeginglEnd 进行绘图,仅此而已.如果您想要快速绘图,您可以将内容放在显示列表中.

Let's take a trip back through the sordid history of OpenGL. Once upon a time, there was OpenGL 1.0. You used glBegin and glEnd to do drawing, and that was all. If you wanted fast drawing, you stuck things in a display list.

然后,有人提出了一个聪明的想法,即能够只使用对象数组进行渲染.因此诞生了 OpenGL 1.1,它为我们带来了诸如 glVertexPointer 之类的功能.您可能会注意到该函数以指针"一词结尾.这是因为它需要指向实际内存的指针,当调用 glDraw* 函数套件之一时,将访问该指针.

Then, somebody had the bright idea to be able to just take arrays of objects to render with. And thus was born OpenGL 1.1, which brought us such functions as glVertexPointer. You might notice that this function ends in the word "Pointer". That's because it takes pointers to actual memory, which will be accessed when one of the glDraw* suite of functions is called.

再快进几年.现在,显卡有能力自行执行顶点 T&L(在此之前,固定功能 T&L 是由 CPU 完成的).最有效的方法是将顶点数据放在 GPU 内存中,但显示列表并不理想.那些太隐蔽了,没有办法知道你是否会得到很好的表现.输入缓冲区对象.

Fast-forward a few more years. Now, graphics cards have the ability to perform vertex T&L on their own (up until this point, fixed-function T&L was done by the CPU). The most efficient way to do that would be to put vertex data in GPU memory, but display lists are not ideal for that. Those are too hidden, and there's no way to know whether you'll get good performance with them. Enter buffer objects.

然而,因为 ARB 有一个绝对的政策,即尽可能地向后兼容(无论 API 看起来多么愚蠢),他们决定实现这一点的最佳方法是再次使用相同的函数.只是现在,有一个全局开关可以将 glVertexPointer 的行为从获取指针"更改为从缓冲区对象中获取字节偏移量".该开关是缓冲区对象是否绑定到 GL_ARRAY_BUFFER.

However, because the ARB had an absolute policy of making everything as backwards compatible as possible (no matter how silly it made the API look), they decided that the best way to implement this was to just use the same functions again. Only now, there's a global switch that changes glVertexPointer's behavior from "takes a pointer" to "takes a byte offset from a buffer object." That switch being whether or not a buffer object is bound to GL_ARRAY_BUFFER.

当然,就C/C++而言,该函数仍然需要一个指针.并且 C/C++ 的规则不允许您将整数作为指针传递.不是没有演员.这就是像 BUFFER_OBJECT 这样的宏存在的原因.这是将整数字节偏移量转换为指针的一种方法.

Of course, as far as C/C++ is concerned, the function still takes a pointer. And the rules of C/C++ do not allow you to pass an integer as a pointer. Not without a cast. Which is why macros like BUFFER_OBJECT exist. It's one way to convert your integer byte offset into a pointer.

(char *)NULL 部分简单地采用 NULL 指针(在 C 中通常是 void* 和在 C++ 中的文字 0)并将其转换为字符*.+ i 只是对 char* 进行指针运算.因为空指针通常有一个零地址,在它上面加上i会使字节偏移量增加i,从而生成一个指针,其值为你传入的字节偏移量.

The (char *)NULL part simply takes the NULL pointer (which is usually a void* in C and the literal 0 in C++) and turns it into a char*. The + i just does pointer arithmetic on the char*. Because the null pointer usually has a zero address, adding i to it will increment the byte offset by i, thus generating a pointer who's value is the byte offset you passed in.

当然,C++ 规范将 BUFFER_OBJECT 的结果列为未定义行为.通过使用它,您实际上是在依赖编译器来做一些合理的事情.毕竟,NULL 并不必须为零;所有规范都说它是一个实现定义的空指针常量.它根本不必具有零值.在大多数真实系统上,它会.但它没有.

Of course, the C++ specification lists the results of BUFFER_OBJECT as undefined behavior. By using it, you're really relying on the compiler to do something reasonable. After all, NULL does not have to be zero; all the specification says is that it is an implementation-defined null pointer constant. It doesn't have to have the value of zero at all. On most real systems, it will. But it doesn't have to.

这就是我只使用演员表的原因.

That's why I just use a cast.

glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)48);

无论哪种方式都不能保证行为(有条件地支持 int->ptr->int 转换,而不是必需的).但它也比输入BUFFER_OFFSET"更短.GCC 和 Visual Studio 似乎觉得合理.并且它不依赖于 NULL 宏的值.

It's not guaranteed behavior either way (int->ptr->int conversions are conditionally supported, not required). But it's also shorter than typing "BUFFER_OFFSET". GCC and Visual Studio seem to find it reasonable. And it doesn't rely on the value of the NULL macro.

就我个人而言,如果我更学究 C++,我会在其上使用 reinterpret_cast.但我不是.

Personally, if I were more C++ pedantic, I'd use a reinterpret_cast<void*> on it. But I'm not.

或者你可以抛弃旧的 API 并使用 glVertexAttribFormat 等.al.,这在各方面都更好.

Or you can ditch the old API and use glVertexAttribFormat et. al., which is better in every way.

这篇关于NULL + int 的结果是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆