【问题标题】:Can I write the address of a variable to any data type in C?我可以将变量的地址写入 C 中的任何数据类型吗?
【发布时间】:2021-04-21 09:05:15
【问题描述】:

我想构建 Linux 命令find 的简化版本。 我正在使用一个结构数组来保存有关我从命令行获得的选项的数据:

struct my_option
{
    short id;              //
    const char *option;    // check valid/invalid option
    short needs_arg;       // check this options requires an argument
    short opt_count;       // count number of paths
    int   first_arg;       // first argument
    int   last_arg;        // last argument
};

static struct my_option opt[] =
{
    {OPT_TYPE     , "-type",    REQUIRES_1_ARGUMENT,        0, 0, 0},
    {OPT_USER     , "-user",    REQUIRES_1_ARGUMENT,        0, 0, 0},
    {OPT_NOUSER   , "-nouser",  REQUIRES_NO_ARGUMENT,       0, 0, 0},
    {OPT_GROUP    , "-group",   REQUIRES_1_ARGUMENT,        0, 0, 0},
    {OPT_NOGROUP  , "-nogroup", REQUIRES_NO_ARGUMENT,       0, 0, 0},
    {OPT_NAME     , "-name",    REQUIRES_1_ARGUMENT,        0, 0, 0},
    {OPT_PATH     , "-path",    REQUIRES_1_ARGUMENT,        0, 0, 0},
    {OPT_PRINT    , "-print",   REQUIRES_NO_ARGUMENT,       0, 0, 0},
    {OPT_LS       , "-ls",      REQUIRES_NO_ARGUMENT,       0, 0, 0},
    {OPT_PATHLIST , 0, 0, 0, 0, 0},
/* OPT_PATHLIST has to be the last entry in the struct */
};

opt[] 的最后一个索引中,您可以看到条目OPT_PATHLIST 和所有其他字段设置为0

如果将多个路径传递给我的 find 命令,我想将它们保存到这个结构中,但我该怎么做呢? 我是否只使用保存实际路径字符串的全局字符串变量并将它们的地址保存到字段_option, _needs_arg, _opt_count, ... 中?我宁愿问,我什至可以这样做吗?将地址保存到任何类型的变量中?

一个例子是: newfind /dev /etc -ls 其中应该打印两个目录/dev/etc中文件的一些信息 如何将保存/dev/etc 的变量的字符串或地址保存到ID 为OPT_PATHLISTstruct my_option

我考虑的另一个选择是: 从命令行输入循环路径 并将它们添加到char *option 上,这样字符串option 最终将是"/dev /etc",而不是使用多个变量作为路径。也许这样会更好更容易。

感谢您的帮助!我这样做是为了大学作业。 编辑:正如有人建议只使用 getopt(3),我不允许这样做。我正在实施 my_getopt()

【问题讨论】:

  • 看来你是在重新发明轮子。见getopt and getopt_long。还有很多现有的库可以提供更高级的命令行选项解析。
  • 使用linux.die.net/man/3/getopt 并为可能有多个实例的选项使用链表或指针数组
  • 为什么要保存它们? argv 不会去任何地方。你只需要索引和计数。
  • 我应该添加:我不允许使用 lib 函数 getopt :( argv 不会去任何地方是真的,我可能只是这样使用它,但这是我的任务,我讨厌说明,因为出于某种原因我必须这样做
  • 你有什么指示?我不清楚你的限制是什么,哪些部分可以更改,哪些部分不能更改。

标签: c linux pointers struct


【解决方案1】:

就我个人而言,我会使用数组作为路径,使用链表作为规则和操作,并使用nftw() 进行目录树遍历。

您可以只为路径重用 argv[] 数组(就像 getopt() 和 getopt_long() 一样),但是一个单独的数组在许多方面更简单:

static size_t   max_paths = 0;
static size_t   num_paths = 0;
static const char **path  = NULL;

void path_add(const char *p)
{
    if (num_paths >= max_paths) {
        size_t  temp_max = num_paths + 16;
        void   *temp;
        temp = realloc(path, temp_max * sizeof path[0]);
        if (!temp) {
            fprintf(stderr, "Out of memory.\n");
            exit(EXIT_FAILURE);
        }
        max_paths = temp_max;
        path = temp;
    }

    path[num_paths++] = p;
}

在上面,num_pathspath[] 数组(这是一个指向每个路径的指针数组)中的路径数,max_paths 是当前分配给的数组条目数。

至于选项/规则/谓词,我会使用单链表,

enum {
    OPT_UNKNOWN = 0,  /* Optional, I just like to reserve zero */
    OPT_TYPE,
    OPT_NAME,
    /* All option types here */
};

struct option {
    struct option *next;
    int            type;
    const char    *arg;
};

您的选项解析循环将检查当前命令行参数,如果被识别,构造一个struct option,其 .type 与该选项的类型匹配,如果该选项为 1,则 .arg 指向其参数,NULL否则。为简单起见,我将以相反的顺序构建列表,然后在处理完所有参数后将其反转:


static struct option  *options = NULL;

static void options_add(int type, const char *arg)
{
    struct option *opt;

    opt = malloc(sizeof *opt);
    if (!opt) {
        fprintf(stderr, "Out of memory.\n");
        exit(EXIT_FAILURE);
    }

    opt->next = options;
    opt->type = type;
    opt->arg  = arg;

    options = opt;
}

static void options_finish(void)
{
    struct option *list = NULL;
    while (options) {
        struct option *curr = options;
        options = options->next;
        curr->next = list;
        list = curr;
    }
    options = list;
}

每当nftw() 调用您的回调函数时,该函数必须遍历选项列表,以确定当前目录条目的处理方式。

【讨论】:

    【解决方案2】:

    为了回答这个问题,我认为您可以使用我们的老朋友 &variable 将变量的地址隐式写入 C 中的任何数据类型。

    【讨论】:

    • 首先,您不能存储所有类型的地址,因为某些类型没有足够的位。例如,一个八位的char 通常没有足够的位来存储几乎所有系统中使用的地址。其次,您不能存储所有类型的地址,因为某些类型没有定义合适的转换。第三,你甚至不能存储所有指针类型的所有地址,因为 C 对指针转换的定义有一些限制。
    猜你喜欢
    • 2012-11-13
    • 2011-07-04
    • 2023-03-20
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 2022-06-15
    • 2013-03-31
    • 1970-01-01
    相关资源
    最近更新 更多