argv中的字符串字面值

4

我的意思是询问在调用execve系列函数时如何保留字符串字面量。来自OSTEP第4章

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

int main (int argc, char *argv[]) {
  ...
  int rc = fork();
  ...
  if (rc == 0) {
    char *myargs[3];
    myargs[0] = strdup("wc");
    myargs[1] = strdup("p3.c");
    myargs[2] = NULL;
    execvp(myargs[0], myargs);
  }

我将...表示为与我的问题无关。 我想问的是这里的代码。 据我了解,C设置myargs以呈现为wc的主函数的char * argv []。 我想了解与字符串字面量有关的概念。 据我了解,C标准允许argv的可变性。 例如:

int main (int argc, char *argv[]) {
  argv[0][2] = 'd';
}

然而,我在想当这些字符数组是固定长度时,如何保证这一点。此外,为什么要调用strdup()?据我理解,这将堆分配该字符串,使其能够被改变,那么在调用execvp()时是否必要呢?还是会:
  myargs[0] = "wc";

可以接受吗?


调用 execvp 将会清除堆,因此不应该有任何影响。这可能是由其他方法保证的(尽管我不能确定)。 - user8393252
1个回答

3
来自OSTEP Chp.4
该链接中的章节标号为5,而不是4。
然而,我想知道当这些字符数组是固定长度时,如何保证这一点。
C标准规定程序可以修改由argv指向的字符串的内容。一个字符串是以(包括)空字符结尾的字符序列。因此,程序可以修改这些字符。因此,它只能保证在程序启动时使用字符串中的字节。不能保证它可以使字符串更长或使用空字符之后的任何字节。
此外,为什么要调用strdup()
因为作者不知道或忽略了这个函数是不必要的事实。
在调用execvp()时,这是否有必要?
不需要,execvp 将采取措施确保传递给它的字符串可供新程序使用。调用 execvp 的程序不需要进行复制。

我想问的是在调用 execve 系列函数时如何保留字符串字面值。

字符串字面量是源代码的一部分。它不是程序中的字符串。字符串字面量是用引号括起来的字符序列,可选地带有前缀u8uUL,例如"abc"u8"def"。字符串字面量就是源代码中那些字符,包括引号。它不是创建程序中的“abc”字符。当程序被编译时,编译器会根据C标准所使用的计算模型创建由字符串字面量表示的字符串。生成的字符串只是一个普通的字符串;与没有来自字符串字面量的字符串相比,它并没有什么特别之处,除了C标准不能保证它可以被修改。有些人称生成的字符串为字符串字面量,但这是语言使用上稍微有些懒散。

无论传递给execvp的字符串是来自字符串字面量,还是由程序构造,或者从输入读取,或者具有自动、静态或动态分配的存储期,都与execvp无关。


我曾经认为字符串字面量是一个地址位置,且内容是只读的。这也是人们指定字符串字面量的方式,以便与可修改的char []字符串区分开来。 - user8393252
2
@user8393252:关于“我曾认为字符串字面量是一个地址位置”的问题:不是的。正如这个答案所解释的那样,字符串字面量是源代码的一部分。 - Eric Postpischil
@user8393252:关于“内容是否只读”的问题是完全无关紧要的,因为execvp不会将其接收到的相同地址传递给新程序(除非仅仅是巧合)。execvp创建了一个全新的程序环境,取代了旧程序。它会执行必要的工作,包括复制字符串。 - Eric Postpischil
我对你的回答感到有些困惑。类似 variable == “hello” 这种语句不会将 "hello" 作为地址吗?而 char *p = “hello”; p[1]=‘o’; 不是未定义行为吗?我问这个问题不是跟这个问题相关,而是一般情况下针对你关于字符串字面值所说的内容。 - user8393252
关于上述内容,如果后者不是一个地址,将 char* 设置为 “hello” 并没有什么意义,或者我有什么误解吗? - user8393252

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接