有人可以向我解释这个代码块中发生了什么吗?特别是在第3行。在ptr显着之前我有预感*。并且(uint8_t *)
看起来像是一个字节...但是什么与*?它看起来像r,g和b都将评估为相同的值。
case TRUECOLOR: { // 24-bit ('truecolor') image (no palette)
uint8_t pixelNum, r, g, b,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
for(pixelNum = 0; pixelNum < NUM_LEDS; pixelNum++) {
r = *ptr++;
g = *ptr++;
b = *ptr++;
strip.setPixelColor(pixelNum, r, g, b);
}
我主要在C#工作。
在变量定义中使用,*
表示ptr
是一个指针。它存储的值是内存中另一个变量或另一个变量的一部分的地址。在这种情况下,ptr
是指向imagePixels
内部的一块内存的指针,并且从涉及的变量的名称开始,它是图像中的一条线。由于类型是uint8_t
,这是采取任何imagePixels
并使用它作为单个字节块。
在变量定义之外使用,*
具有不同的含义:取消引用指针。转到存储在指针中的内存中的位置并获取值。
是的,*
也可以用于乘法,提高代码阅读乐趣水平。
递增(++
)指针会将地址移动到下一个地址。如果你有一个uint32_t *
,地址将提前4点指向下一个uint32_t
。在这种情况下,我们有uint8_t
,所以地址提前一个字节。所以
r = *ptr++;
A)获得指针值。
A)推进指针后。
A)将值赋值给r。
“推进指针”阶段的确切位置是棘手的。它是在步骤A之后。在C ++ 17或更高版本中,它位于“赋值”之前,因为右边的东西和等号左边的东西之间存在分隔。但在C ++ 17之前我们可以说它是在A步之后。搜索关键词:“序列点”。
g = *ptr++;
b = *ptr++;
再做一次,获取并分配ptr
的当前值,推进指针。
strip.setPixelColor(pixelNum, r, g, b);
从命名我假设这将给定像素设置为上面读取的颜色。
你不能只是
strip.setPixelColor(pixelNum, *ptr++, *ptr++, *ptr++);
因为再次排序。无法保证计算参数的顺序。这是为了允许编译器开发人员对速度和大小进行优化,如果指定了排序则不能对它们进行优化,但对于那些期望从左到右分辨率的人来说,这是一个很好的选择。我的理解是这在C ++ 17标准中仍然适用。
好。这是做什么的?
有一个很大的内存块,你想要一个只有一行。
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
精确定位该行的开头并将其设置为一个哑字节数组。
for(pixelNum = 0; pixelNum < NUM_LEDS; pixelNum++) {
通用for
循环。对于LED线上的所有像素。
r = *ptr++;
g = *ptr++;
b = *ptr++;
以标准8位RGB格式获取线上一个像素的颜色,并指向下一个像素
strip.setPixelColor(pixelNum, r, g, b);
将读取的颜色写入一个像素。
然后for
循环将循环并开始处理下一个像素,直到该行上没有更多像素。
第二行和第三行可以更清晰地表达:
uint8_t pixelNum;
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t *ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
前四个变量声明应该相当简单,第五个变量声明是C#没有的。它宣称ptr
是指向uint8_t
的指针。该指针设置为值的地址,该值是imageLine * NUM_LEDS * 3
数组中的imagePixels
th元素。因为这可能是一个不同的类型(也许是指向char
的指针,谁知道),这个值被强制转换为指向uint8_t
的指针。
下一个星号(*
)出现在for循环体中,它用作解除引用操作符,它基本上解析了一个指针来获取实际值。
指针就像房子的街道地址。它告诉你房子在哪里,你可以找到它,但当你传递它时,你不会绕过整个房子。您可以取消引用它,这意味着您实际上可以访问该房屋。
与指针结合使用的两个运算符是星号(*
)和&符号(&
)。星号用于指针的声明和取消引用指针,&符号用于获取某些东西的地址。
看一下下面的例子:
int x = 12;
int *y = &x;
std::cout << "X is " << *y; // Will print "X is 12"
我们宣布x
为持有int
值的12
。现在我们将y
声明为指向int
的指针,并通过存储x
的地址将其设置为指向x
。通过使用*y
,我们获得x
的实际值,int
指向的y
。
由于指针是一种引用类型,因此通过指针修改值会改变指向的事物的实际值。
int x = 12;
int *y = &x;
*y = 10;
std::cout << "X is " << x; // Will print "X is 10"
指针是一个很大的主题,如果有必要,我建议你花时间从不同的来源阅读它们。
星号(*)是指针的符号。所以(uint8_t *)是指向uint8_t的指针的强制转换。然后在循环中,星号前缀为一个符号(即* ptr),该符号取消引用该指针。取消引用指针会返回指针指向的数据。
我建议阅读有关指针的内容,因为它们对于理解C / C ++至关重要。这是C++ Docs on Pointers
MildlyInformed,我需要更多代码来运行它来解释它。我发现的一个非常有用的工具是C visualizer。它是一个在线调试工具,通过逐步逐行运行,帮助您弄清楚代码中发生了什么。它可以在:http://www.pythontutor.com/visualize.html#mode=edit找到
即使URL谈到python,它也可以做C和一堆语言。我会评论而不是发布答案,但我的代表不够高。我希望这有帮助!
(我不隶属于上述网站,除了在我感到困惑时偶尔使用它)