手动构造完全与`char *argv[]` 等价的参数

场景

在main函数中的两个参数(int argc , char *argv[]),都是系统构造的。通常来说,我们只需要去解析即可,不需要去构造这样一个参数。

然而,今天写代码时却不得不构造这样一个参数。原因是使用了一个第三方的模块(准确的说是基于第三方模块),第三方模块初始化时需要接受(int argc , char ** &argv)这样的参数。注意到其中的引用符号!

通常来说,直接传递main函数的argc , argv是没有问题的。事实也确实如此,传递main函数接受的argv不会有编译错误。不过有些坑就是,这个模块自己参数解析写得太武断!就是不允许有多余的参数项!一旦有多余参数项就会导致其停止解析参数,最终导致其解析失败。然而我的程序除了给这个模块传参数,还需要额外的参数啊!

没有办法,我就得自己构造仅仅包含第三方模块需要的参数argv , 但是狗血的事情出现了!

怎么构造就是不行!!编译一直报错:

用类型为‘char**’的右值初始化类型为‘char**&’的非常量引用无效

经过一系列的修改,终于正确编译了。

一切的狗血,都是因为概念理解的不清晰。

解决方案

只考虑argv的构造:

int fack_main(int argc , char **&argv);

int fack_argc = 2 ;
char arg0[] = "program name" ;
char arg1[] = "arg1 for thirdparth" ;
char **fake_argv = new char *[fack_argc+1]{ arg0 , arg1 } ;

fack_main(fack_argc , fack_argv) ; 

delete [] fack_argv ;

以上就是完整的构造过程。这样构造的fack_argv应该与main函数中的argv完全等价的。

解决过程

解决过程就很辛酸了。

  1. raw

    fack_argv[2][100] { "program name" , "arg1"  } ;
    
    fack_main(fack_argc , fack_argv) ; 

    报错:

    用类型为‘char (*)[100]’的右值初始化类型为‘char**&’的非常量引用无效

    看到这个错误还是很好理解的。说明参数传递时fack_argv还是是一个指向char[100]的指针类型char (*)[100],不是char **&

    想到的解决办法是static_cat

  2. static_cast
    fack_argv[2][100] { "program name" , "arg1" } ;
    fack_main(fack_argc , static_cast<char **>(fack_argv)) ; 

    结果报错:

    从类型‘char [3][100]’到类型‘char**’中的 static_cast 无效

    为何强制转换会失效呢?

    难道只能一步步转换?

    试了以下代码:

    fack_main(argc , static_cast<char **>(static_cast<char(*)[100]>(f_argv))) ; 

    想要通过两步完成,但是依然报错:

    错误:从类型‘char (*)[100]’到类型‘char**’中的 static_cast 无效

    这说明从一维数组到指针是OK的,但是第二步就失败了。一想,第二步时,代码其实是在将一个指向数组的指针转为一个指向指针的指针。这或许是编译器不支持的。

    失败之后,再一想,既然直接声明二维数组失败了,那么看来只有声明一个一维的数组,数组里放char *就好了。

  3. 指向指针(char*)的数组
    char arg0[] = "program name" ;
    char arg1[] = "arg1" ;
    char *fake_argv[2] = { arg0 , arg1  } ;

    结果还是报错:

    错误:用类型为‘char**’的右值初始化类型为‘char**&’的非常量引用无效

    这次需要注意了,前面已经对了——我们已经构造了char**,无奈目标是 char **& 。但是奇怪的是,传main的argv就不会报错,那说明这二者间还是有差别的!

    需要继续改!

    这次着眼于后边部分——”非常量引用”!

    是不是说char **可以转换为常量引用啊?

  4. 测试:将char *[] 转为常量引用

    鼓捣了半天,终于弄明白常量引用如何声明:

    char *fake_argv[2] = { arg0 , arg1  } ;
    char ** const (&ra) = fake_argv ;

    通过!

    从上面可以看出,所谓常量引用,是要求一个底层const,就是说ra的值不能改变。

    这个测试对问题而言帮助不大,但是隐式地说明——还是变量类型声明出了问题。

    网上搜索!

  5. 网上搜索argv *[]

    查看 Defining own main functions arguments argc and argv

    发现了问题是相似的,但是提供的解决办法依然不能解决形参是car **&的问题。

    不过收获到:argv最后要多一个NULL结束标志

  6. 完全的类型一致!

    既然是说char **char **&错误,但是我的实参依然是个数组,这说明编译器已经做了隐式转换。

    我记得在类的构造函数中说过,类的隐式转换最多一次。

    有没有这种可能:

    值参数到引用参数,其实也是一个隐式转换

    再加上前面的猜测——最多一次隐式转换,问题就明白了。一次隐式转换用来将char *argv[]变为char **argv,所以就导致了char **char **&的失败。

    书读得不多,我觉得应该会有相关介绍的。这里只是猜测。

    这样,就有了最后的方案:

    int fack_main(int argc , char **&argv);
    
    int fack_argc = 2 ;
    char arg0[] = "program name" ;
    char arg1[] = "arg1 for thirdparth" ;
    char **fake_argv = new char *[fack_argc+1]{ arg0 , arg1 } ;
    
    fack_main(fack_argc , fack_argv) ; 
    
    delete [] fack_argv ;

    通过编译!问题解决。

时间: 2024-10-27 18:16:35

手动构造完全与`char *argv[]` 等价的参数的相关文章

int main (int argc, const char * argv[0]) 中参数的含义;指针数组和数组指针

恩,有的编译器初始化时候会产生这样的参数 argc是命令行总的参数个数,argv[]是argc个参数,其中第0个参数是程序的全名 1. 几种C++ 常见的参数种类 int main(void); int main(); int main(int argc, char **argv);   //等价于int main(int argc, char *argv[]),是否等价呢?是不是前一个可以表示任意长度的任意个数组,后一个只是定长的任意个数的数组?见下面 int main(int argc, c

int main(int argc,char*argv[])

通常我们见到的main函数都是不带参数的,实际上,main函数也可以带参数.main函数的参数是由谁传来的呢?答案是操作系统,C++规定main函数的参数只能有两个,即argc和argv,带参main函数的形式如下所示. int main(int argc,char*argv[]) { …… } 第一个参数argc必须是整型变量,称做参数计数器,其值是包括命令名在内的参数个数: 第二个参数argv必须是指向字符指针数组,存放命令名和参数字符串的地址. 要调用带参主函数必须在操作系统环境下进行,参

cmd的基本使用_针对C++程序的运行main(int argc, char* argv[])

对于cmd的指令我一窍不通,今天见学长用了,记录下: >cd  文件名       //到该文件下 文件地址加>dr    //得到该文件的目录 文件地址加>文件名.exe   //运行该文件,是C++程序产生的.exe文件 ///如果.cpp的main为main(int argc, char* argv[]) 文件地址加>文件名.exe  1.jpg  2.jpg  3.jpg    ///argc是空格数  argv是 1.jpg  2.jpg  3.jpg 字符串

main()函数的输入参数 main(int argc, char** argv)

一般简单的C++程序,main函数的写法都是 int main() {... ; return 0;},但是,如果在运行程序时需要有参数输入,可以是使用将主函数写成int main(int argv, char** argv)的形式. 如测试程序如下: #include <iostream> using namespace std; int main(int argc, char** argv) { for(int i = 0; i<argc; i++) cout << ar

int main(int argc, char * argv[]) 里的异常处理

#import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { @try { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } @catch (NSException *exception) { NSLog(@&qu

int mainargc,char *argv[])详解

argc是命令行总的参数个数 argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数     命令行后面跟的用户输入的参数,比如:     int   main(int   argc,   char*   argv[])     {     int   i;     for   (i   =   0;   i<argc;   i++)     cout<<argv[i]<<endl;     cin>>i;     return   0;     }

int main(int argc,char* argv[])详解

argc是命令行总的参数个数     argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数     命令行后面跟的用户输入的参数,比如:     int   main(int   argc,   char*   argv[])     {     int   i;     for   (i   =   0;   i<argc;   i++)     cout<<argv[i]<<endl;     cin>>i;     return   0;  

主函数main中变量(int argc,char *argv[ ])的含义

在OpenCV上看到一段处理视频的代码,但是复制到VS下运行运行框总是闪退,查了一下原来应该直接在命令下运行exe文件,主要涉及main函数中argc和argv参数的意义,在这里说一下 argc: 整数,用来统计你运行程序时送给main函数的命令行参数的个数 * argv[ ]: 字符串数组,用来存放指向你的字符串参数的指针数组,每一个元素指向一个参数 argv[0] 指向程序运行的全路径名 argv[1] 指向在DOS命令行中执行程序名后的第一个字符串 argv[2] 指向执行程序名后的第二个

38&gt;&gt;int main( int argc, char **argv)

1.参数 (有时参数是void) argc是程序运行时参数个数 argv是存储参数的数组,可以用char* argv[],也可以用char **argv. 例如编译一个hello.c的程序 1 #include<stdio.h>  2 int main(int argc,char *argv[])  3 {  4     printf("%d\n",argc);  5     printf("%s\n",argv[0]);  6     /*printf