【问题标题】:Syntax for passing a const char parameter to static char *argv[] in C在 C 中将 const char 参数传递给 static char *argv[] 的语法
【发布时间】:2015-04-01 06:46:03
【问题描述】:

好的,我正在尝试构建一个守护程序(用于 Debian 机器),它将接收它(通过 cron)接收的命令行参数并将它们传递给不同的脚本文件。

守护进程的main()

 int main(int argc , char *argv[])
 {
        if(argc != 3)
        {
            exit(0);
        }

        daemonize(argv[1], argv[2]);

    return 0;
 }

并且函数 daemonize 有这个设置

int daemonize(const char *cmd1, const char *cmd2) {...}

daemonize 中令人不安的部分在这里:

if (strcmp(cmd1,"sample_script") == 0)
    {
        static char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };
        execv("/etc/init.d/sample_script",argv);
        exit(127);
    }

上线

static char *argv[] = {"/etc/init.d/sample_script", ("%s",cmd2), NULL };

我收到了这个错误

initializer 元素不是常量('argv[1]' 的初始化附近)

显然("%s",cmd2) 是错误的。因为使用“开始”可以正常工作。

那么,如何让cmd2 正确放入*argv[]?还是我做错了什么?

【问题讨论】:

  • 你需要函数参数为 const char *
  • 你确定你的argv 值在daemonize 函数中是正确的。由于您的*argv[] = {"/etc/init.d/sample_script", ...} 并将其传递给execv,因此/etc/init.d/sample_script 被重复两次,相当于在命令行中以/etc/init.d/sample_script /etc/init.d/sample_script .. 运行。如果您可以提供示例输入和预期输出,那就更容易了
  • 初始化器中的 [ ...] 符号应该是什么?
  • @JensGustedt 谢谢你的提问。基本上,daemonize 函数会进行双重分叉,因此父进程位于 init 中。然后它将调用不同的脚本(取决于 cmd1)并将 cmd2 传递给它们。这样,这些脚本也只有 init 作为父进程。无论如何,这就是计划。
  • 我的问题更基本,您提供的语法对我来说毫无意义。事实上,您使用的是一个 designated initializer,其中包含一个逗号表达式。这肯定不是你想要的。

标签: c arrays pointers exec


【解决方案1】:

你需要改变

static char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };

const char *argv[] = {"/etc/init.d/sample_script", cmd2, NULL };

您必须删除 static 关键字。根据第 6.7.9 章,C11 标准,

具有static 或线程存储持续时间的对象的初始化程序中的所有表达式 应该是常量表达式或字符串文字。

也就是说,在 C 语言中,具有 static 存储持续时间的对象必须使用 常量表达式 或包含常量表达式的聚合初始化器进行初始化。

并且,关于常量表达式,来自同一文档的第 6.6 章

可以在翻译期间而不是运行时评估常量表达式,并且 因此可以在常量可能存在的任何地方使用。

因此,在C 中,一个变量(名称),即使声明为const,也绝不是一个常量表达式


编辑:

要解决最新的问题,您可以尝试以下方法

  1. 更改int daemonize(char *cmd1, char *cmd2) {..
  2. 使用char * const argv[] = {"/etc/init.d/sample_script", cmd2, NULL };

您可以保持其余代码不变。

【讨论】:

  • 感谢您的回答。不幸的是,这就是我最初拥有的。但它没有用。给出了同样的错误。
  • @mycowan 在初始化期间可以使指针指向另一个指针,并且 sourav 显示的内容是正确的。我认为这里不需要NULL。摆脱它
  • @Gopi,感谢您的帮助。我试过 {"/etc/init.d/sample_script", cmd2};但仍然是同样的错误。
  • @mycowan 我想我们都错过了第 6.7.9 章。让我修改一次。
  • @SouravGhosh - 感谢您的提醒。但是新的错误是 warning: 从不兼容的指针类型传递 'execv' 的参数 2 [默认启用] 在 daemonizer.c:4:0: /usr/include/unistd.h:560:12 包含的文件中:注意:预期为 'char * const*' 但参数的类型为 'const char **'
【解决方案2】:

execv 的函数声明是

int execv(const char *path, char *const argv[]);

第二个参数的正确解释是 "constchar *" 数组,它不同于 "const char *" 数组。换句话说,execv 保留更改数组指向的字符串内容的权利,但不会更改数组中的任何指针。

也就是说argv数组中的所有字符串都必须在可写内存中。因此,为了在技术上完全正确,代码应该制作所有字符串的可写副本,就像这样

if (strcmp(cmd1,"sample_script") == 0)
{
    char arg0[] = "/etc/init.d/sample_script";
    char *arg1 = strdup( cmd2 );

    char *argv[] = { arg0, arg1, NULL };
    execv( argv[0], argv );
    exit(127);
}

【讨论】:

  • @user3386106 - 快点 v(^.^)v - 你的代码成功了!我收到关于内置函数'strdup'_的_不兼容隐式声明的警告,所以我不得不添加#include 但是-所有编译和sample_script都运行了。非常感谢!
【解决方案3】:

您不能使用仅在运行时知道的变量/参数来初始化静态变量。

离开static

char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };

【讨论】:

  • 感谢您的帮助,但这是新错误 - 警告:初始化会丢弃指针目标类型中的“const”限定符 [默认启用]
  • @mycowan,你确定你使用的是 C 编译器而不是 C++ 编译器吗?
  • 老实说,我正在从各地收集零碎的代码。这个项目是我编码技能的极限。目标机器是一个用于遥感设备的精简 linux 机器(Debian - 在任何人开始之前 - 在我到达这里之前就做出了决定),所以我希望我不会放任何 C++ 代码。我正在使用 gcc 进行编译。我希望那是正确的。 (Java 人——他只使用 C,因为守护进程将在最低运行级别运行,并且只有 C 在那里工作——我相信)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-20
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 2013-12-19
  • 1970-01-01
相关资源
最近更新 更多