【问题标题】:Is repetitively creating buffers on the stack in a loop in C bad practice?在 C 循环中重复在堆栈上创建缓冲区是不好的做法吗?
【发布时间】:2020-07-10 15:40:45
【问题描述】:

这篇文章的标题与我搜索的相关内容非常相似。我遇到的每个结果都是关于缓冲区溢出的,而这不是我想要的。

我的函数在我之前填充的不同结构中迭代每个文件名。每个文件名的大小各不相同,从非常小到非常大。

以前我的函数会做的是创建缓冲区,大小为 2048 字节。然后进入循环。 在循环的每次迭代期间,缓冲区都填充有目标目录的路径,以及连接到其末尾的目录中的当前文件名。 使用缓冲区中的新路径,我执行了一些相当小的文件操作。 这种情况会一直发生,直到达到结构中的最终文件名。

然而,问题在于并非每个完整路径都是 2048 字节。有些可能甚至不到这个大小的三分之一。

重新访问这个函数,我将缓冲区的创建移到循环内,循环的每次迭代都会创建大小为n 的缓冲区,其中nthe length of the target directory + the length of the current filename within the directory

我想知道这是否会被认为是不好的做法或其他任何事情。我是否最好事先创建缓冲区并始终为其设置大小,即使有时 2/3 的缓冲区未使用?还是只为我需要的大小创建缓冲区是一个更好的主意?

我希望我已经提供了足够的信息...在此先感谢!

这是有问题的函数。

int verifyFiles(DIR *dp, const char *pathroot){
    struct dirent *dir;
    struct stat pathstat;
    //char path[2048];
    int status = 0;

    while((dir = readdir(dp)) != NULL){
        if(!strncmp(dir->d_name, ".", 1))
            continue;

        size_t len = strlen(pathroot) + strlen(dir->d_name) + 2;
        char path[len];
        snprintf(path, sizeof(path), "%s/%s", pathroot, dir->d_name);
        
        // verify shebang is present on the first line of path's contents.
        if(!shebangPresent(path)){
            status = -1;
            break;
        }

        // verify path belongs to the user.
        stat(path, &pathstat);
        if(pathstat.st_uid != getuid()){
            status = -1;
            break;
        }
    }

    return status;
}

【问题讨论】:

  • 如果您发布您现在拥有的代码,至少可以帮助我理解您的问题。
  • “问题是” - 真的有问题吗?如果是这样,怎么做?不要修复没有损坏的东西。
  • 更新了示例代码。谢谢。 @klutt 当然,如果我倾向于不浪费不必要的空间,这只是更好的做法吗?这不是坏事或工作的问题。这是一个尽可能提高效率的问题。如果这是我可以让我的代码更高效的地方,那么我应该知道......

标签: c performance while-loop stack buffer


【解决方案1】:

拥有这样的固定缓冲区绝对没有错。不要担心这些小细节。该函数将分配 2kB 的内存,完成它的工作,然后释放它。如果这是一个问题,那么你的问题比这段代码更大。

我只会在递归函数的情况下担心这些事情。就像你有这样的东西:

int foo(int n) 
{
    char buf[2048];
    int r = foo(n-1);
    // Do something with buf and return
}

上面的代码会很快吃掉大 n 的堆栈。但在你的情况下,我真的不会担心,直到你有一些证据或至少有合理的怀疑它确实导致了问题。

如果它是一个更大的缓冲区,比如大约 100kB,那么我肯定会使用动态分配。该堆栈在 Windows 上通常有 1MB,在 Linux 上通常有 8MB。所以这不是“不浪费内存”的问题,而是不炸毁堆栈。

【讨论】:

  • 感谢您的回复,非常感谢。
【解决方案2】:

在 C 的循环中重复在堆栈上创建缓冲区是不好的做法吗?
我想知道这是否会被认为是不好的做法或其他任何事情。

不,char path[len]; 不是问题。

然而,这里用来确定缓冲区大小的方法很弱。

下面的代码repeatedly calculatespathroot的字符串长度。也许,一个好的编译器可能会分析并发现不需要重复调​​用。很容易确保计算一次完成。

size_t pathlen = strlen(pathroot); // add

while((dir = readdir(dp)) != NULL){
    if(!strncmp(dir->d_name, ".", 1))
        continue;

    // size_t len = strlen(pathroot) + strlen(dir->d_name) + 2;
    size_t len = pathlen + strlen(dir->d_name) + 2;

    char path[len];

我是否最好事先创建缓冲区并始终为其设置大小,即使有时 2/3 的缓冲区未使用?

这种的情况下,路径大小可能有一个环境上限:可能是MAXPATHMAXPATHLEN

我会考虑以下内容以避免重复复制路径 - 它可能会很长。

char path[MAXPATH + 1];  // or malloc()
int len = snprintf(path, sizeof path, "%s/", pathroot);
if (len < 0 || len >= sizeof path) Handle_OutOfRoom();

while((dir = readdir(dp)) != NULL){
  int len2 = snprintf(path + len, sizeof path - len, "%s", dir->d_name);
  if (len2 < 0 || len2 >= sizeof path - len) Handle_OutOfRoom();
  ...

【讨论】:

    猜你喜欢
    • 2012-12-25
    • 2021-12-29
    • 2014-04-22
    • 2019-05-25
    • 1970-01-01
    • 2013-12-09
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多