为什么可以在嵌套循环中声明一个 STRUCT?
Why is it okay to declare a STRUCT inside a nested loop?
这是一些提供的 (CS50) 代码片段,它在嵌套循环内一遍又一遍地声明相同的结构 'triple'。为什么这样可以?在我看来,在嵌套循环的范围之上声明 STRUCT 'triple' 并在每次迭代中更改值会更有效。
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
.
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// write RGB triple to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
在大多数情况下,此级别的效率是编译器关心的问题。编译器很可能会为每个 RGBTRIPLE 重用相同的堆栈 space! (虽然不一定。)
将 RGBTRIPLE 放在需要它的最小括号对(作用域)内可以防止您意外地、错误地访问该作用域外的变量,此时变量的内容可能无效。
Still, are thousands of iterations of the same declaration is better than a single declaration right before the first loop?
当然可以。无论哪种方式,一个好的编译器都不会发出有任何性能差异的代码。
适度 线性 性能变化可能是调用 fread()
的频率降低。
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++) {
RGBTRIPLE triple[bi.biWidth];
fread(triple, sizeof triple, 1, inptr);
fwrite(triple, sizeof triple, 1, outptr);
}
甚至
RGBTRIPLE triple[biHeight][bi.biWidth];
fread(triple, sizeof triple, 1, inptr);
fwrite(triple, sizeof triple, 1, outptr);
很多因素都需要考虑编码。避免专注于诸如此类的微优化。
这里要理解的重要一点是,语句 RGBTRIPLE triple;
声明了变量,但并不直接对应于 "creating storage," 或者实际上根本不转换为任何机器语言输出。
您只是向编译器声明此变量的作用域和用法(在最局部的块内声明是一种很好的做法,表明您只希望它在该区域内有效)。您可以将这一行放在循环之外,或者放在它的函数的顶部,而不更改可执行输出。
编译器的工作是在堆栈上有效地创建 space 以供运行时使用局部变量。在实践中,它将简单地重用在每个循环迭代中一遍又一遍使用的相同 space。 (这里的人会正确地告诉你,这不是 保证 的行为,这在技术上是正确的,但实际上它总是会重复使用相同的 space,就好像你' d 在循环之上声明它。)
这是一些提供的 (CS50) 代码片段,它在嵌套循环内一遍又一遍地声明相同的结构 'triple'。为什么这样可以?在我看来,在嵌套循环的范围之上声明 STRUCT 'triple' 并在每次迭代中更改值会更有效。
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
.
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// write RGB triple to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
在大多数情况下,此级别的效率是编译器关心的问题。编译器很可能会为每个 RGBTRIPLE 重用相同的堆栈 space! (虽然不一定。)
将 RGBTRIPLE 放在需要它的最小括号对(作用域)内可以防止您意外地、错误地访问该作用域外的变量,此时变量的内容可能无效。
Still, are thousands of iterations of the same declaration is better than a single declaration right before the first loop?
当然可以。无论哪种方式,一个好的编译器都不会发出有任何性能差异的代码。
适度 线性 性能变化可能是调用 fread()
的频率降低。
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++) {
RGBTRIPLE triple[bi.biWidth];
fread(triple, sizeof triple, 1, inptr);
fwrite(triple, sizeof triple, 1, outptr);
}
甚至
RGBTRIPLE triple[biHeight][bi.biWidth];
fread(triple, sizeof triple, 1, inptr);
fwrite(triple, sizeof triple, 1, outptr);
很多因素都需要考虑编码。避免专注于诸如此类的微优化。
这里要理解的重要一点是,语句 RGBTRIPLE triple;
声明了变量,但并不直接对应于 "creating storage," 或者实际上根本不转换为任何机器语言输出。
您只是向编译器声明此变量的作用域和用法(在最局部的块内声明是一种很好的做法,表明您只希望它在该区域内有效)。您可以将这一行放在循环之外,或者放在它的函数的顶部,而不更改可执行输出。
编译器的工作是在堆栈上有效地创建 space 以供运行时使用局部变量。在实践中,它将简单地重用在每个循环迭代中一遍又一遍使用的相同 space。 (这里的人会正确地告诉你,这不是 保证 的行为,这在技术上是正确的,但实际上它总是会重复使用相同的 space,就好像你' d 在循环之上声明它。)