c 编程 - 从 ‘void*’ 到“record_s*”的无效转换

标签 c error-handling directory-listing

我从 StackOverflow 获得了代码。我在 GCC 下用 raspbian 编译我的代码。我的文件的扩展名是cpp。当我编译代码时,出现以下错误: 我提到,如果有任何有用的代码可以以最快和最正确的方式列出给定路径和给定深度中的所有文件和目录,我将不胜感激。我认为这段代码可以以正确且快速的方式索引文件和文件夹。当您回答这个问题时,请提供完整的代码和 raspbian 的编译命令。

 error: invalid conversion from ‘void*’ to ‘record_s* {aka main(int, const char**)::record_s*}’ [-fpermissive]
   pos = malloc(sizeof(*pos) + strlen(argv[1]) + 2);
         ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cpp_list_directory.cpp:125:55: error: ‘struct dirent’ has no member named ‘d_namlen’; did you mean ‘d_name’?
       item = malloc(sizeof(*item) + pos->len + entry->d_namlen + 2);
                                                       ^~~~~~~~
cpp_list_directory.cpp:127:37: error: ‘struct dirent’ has no member named ‘d_namlen’; did you mean ‘d_name’?
       item->len = pos->len + entry->d_namlen;
                                     ^~~~~~~~
cpp_list_directory.cpp:129:59: error: ‘struct dirent’ has no member named ‘d_namlen’; did you mean ‘d_name’?
       memcpy(item->name + pos->len, entry->d_name, entry->d_namlen);

我的代码是:

#include <dirent.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

int main(int argc, char const *argv[]) {
  /* print use instruction unless a folder name was given */
  if (argc < 2)
    fprintf(stderr,
            "\nuse:\n"
            "    %s <directory>\n"
            "for example:\n"
            "    %s ./\n\n",
            argv[0], argv[0]),
        exit(0);

  /*************** a small linked list macro implementation ***************/

  typedef struct list_s {
    struct list_s *next;
    struct list_s *prev;
  } list_s;

#define LIST_INIT(name)                                                        \
  { .next = &name, .prev = &name }

#define LIST_PUSH(dest, node)                                                  \
  do {                                                                         \
    (node)->next = (dest)->next;                                               \
    (node)->prev = (dest);                                                     \
    (node)->next->prev = (node);                                               \
    (dest)->next = (node);                                                     \
  } while (0);

#define LIST_POP(list, var)                                                    \
  if ((list)->next == (list)) {                                                \
    var = NULL;                                                                \
  } else {                                                                     \
    var = (list)->next;                                                        \
    (list)->next = var->next;                                                  \
    var->next->prev = var->prev;                                               \
  }

  /*************** a record (file / folder) item type ***************/

  typedef struct record_s {
    /* this is a flat processing queue. */
    list_s queue;
    /* this will list all queued and processed folders (cyclic protection) */
    list_s folders;
    /* this will list all the completed items (siblings and such) */
    list_s list;
    /* unique ID */
    ino_t ino;
    /* name length */
    size_t len;
    /* name string */
    char name[];
  } record_s;

/* take a list_s pointer and convert it to the record_s pointer */
#define NODE2RECORD(node, list_name)                                           \
  ((record_s *)(((uintptr_t)(node)) -                                          \
                ((uintptr_t) & ((record_s *)0)->list_name)))

/* initializes a new record */
#define RECORD_INIT(name)                                                      \
  (record_s){.queue = LIST_INIT((name).queue),                                 \
             .folders = LIST_INIT((name).folders),                             \
             .list = LIST_INIT((name).list)}

  /*************** the actual code ***************/

  record_s records = RECORD_INIT(records);
  record_s *pos, *item;
  list_s *tmp;
  DIR *dir;
  struct dirent *entry;

  /* initialize the root folder record and add it to the queue */
  pos = malloc(sizeof(*pos) + strlen(argv[1]) + 2);
  *pos = RECORD_INIT(*pos);
  pos->len = strlen(argv[1]);
  memcpy(pos->name, argv[1], pos->len);
  if (pos->name[pos->len - 1] != '/')
    pos->name[pos->len++] = '/';
  pos->name[pos->len] = 0;
  /* push to queue, but also push to list (first item processed) */
  LIST_PUSH(&records.queue, &pos->queue);
  LIST_PUSH(&records.list, &pos->list);

  /* as long as the queue has items to be processed, do so */
  while (records.queue.next != &records.queue) {
    /* pop queued item */
    LIST_POP(&records.queue, tmp);
    /* collect record to process */
    pos = NODE2RECORD(tmp, queue);
    /* add record to the processed folder list */
    LIST_PUSH(&records.folders, &pos->folders);

    /* process the folder and add all folder data to current list */
    dir = opendir(pos->name);
    if (!dir)
      continue;

    while ((entry = readdir(dir)) != NULL) {

      /* create new item, copying it's path data and unique ID */
      item = malloc(sizeof(*item) + pos->len + entry->d_namlen + 2);
      *item = RECORD_INIT(*item);
      item->len = pos->len + entry->d_namlen;
      memcpy(item->name, pos->name, pos->len);
      memcpy(item->name + pos->len, entry->d_name, entry->d_namlen);
      item->name[item->len] = 0;
      item->ino = entry->d_ino;
      /* add item to the list, right after the `pos` item */
      LIST_PUSH(&pos->list, &item->list);

      /* unless it's a folder, we're done. */
      if (entry->d_type != DT_DIR)
        continue;

      /* test for '.' and '..' */
      if (entry->d_name[0] == '.' &&
          (entry->d_name[1] == 0 ||
           (entry->d_name[1] == '.' && entry->d_name[2] == 0)))
        continue;

      /* add folder marker */
      item->name[item->len++] = '/';
      item->name[item->len] = 0;

      /* test for cyclic processing */
      list_s *t = records.folders.next;
      while (t != &records.folders) {
        if (NODE2RECORD(t, folders)->ino == item->ino) {
          /* we already processed this folder! */
          break; /* this breaks from the small loop... */
        }
        t = t->next;
      }
      if (t != &records.folders)
        continue; /* if we broke from the small loop, entry is done */

      /* item is a new folder, add to queue */
      LIST_PUSH(&records.queue, &item->queue);
    }
    closedir(dir);
  }

  /*************** Printing the results and cleaning up ***************/
  while (records.list.next != &records.list) {
    /* pop list item */
    LIST_POP(&records.list, tmp);
    /* collect record to process */
    pos = NODE2RECORD(tmp, list);
    /* prepare for next iteration */
    LIST_POP(&records.list, tmp);
    fwrite(pos->name, pos->len, 1, stderr);
    fwrite("\n", 1, 1, stderr);
    free(pos);
  }
  return 0;
}

我使用以下命令在 gcc 中编译代码:

g++ -Wall cpp_list_directory.cpp -o cpp_list_directory

最佳答案

编译器告诉您(在您的平台上)字段:d_namelen未在struct dirent中实现

这是struct dirent的定义

struct dirent {
    long d_ino;
    off_t d_off;
    unsigned short d_reclen;
    char d_name[1];
}; 

但是您的代码可以通过以下方式获取文件名的长度:

DIR *directoryEntry;
size_t length = strlen( directoryEntry->d_name );

有关 void* 等的消息是由于您使用 C++ 造成的。 (那么为什么问题上的 c 标签而不是 c++

关于c 编程 - 从 ‘void*’ 到“record_s*”的无效转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53777254/

相关文章:

c++ - C++ 的文件系统迭代器

c - c 中的简单字符串列表正在泄漏内存(malloc 和 realloc)

c - 父进程终止后如何杀死所有子进程?

java - 设置命令行 Java 错误日志?

actionscript-3 - AS3警告: Class 'Main' does not extend the 'DefineBits' asset base class 'flash.display.Bitmap or flash.display.BitmapData'

javascript - 如何获取 Node.js 目录中存在的所有文件的名称列表?

c++ - 如何减少这个问题的执行时间(即更快的代码)

c - 如何使用c从csv文件中获取具有精确数据的特定行?

javascript - 如何判断回调中错误的真正原因?

python - 如何在 Python3.x 中检索单个 7zip 文件而不解压所有文件?