如何从optarg获取一个值

9

嗨,我正在编写一个简单的客户端-服务器程序。在这个程序中,我必须使用getopt()来获取端口号和IP地址,像这样:

server -i 127.0.0.1 -p 10001

我不知道如何从optarg获取值,以便稍后在程序中使用。

4个回答

17
你使用while循环来遍历所有参数并进行处理,如下所示...
#include <unistd.h>

int main(int argc, char *argv[])
{
    int option = -1;
    char *addr, *port;

    while ((option = getopt (argc, argv, "i:p:")) != -1)
    {
         switch (option)
         {
         case 'i':
             addr = strdup(optarg);
             break;
         case 'p':
             port = strdup(optarg);
             break;
         default:
              /* unrecognised option ... add your error condition */
              break;
         }
    }

    /* rest of program */

    return 0;
}

4
如果在退出程序之前不释放内存,strdup会导致内存泄漏。因此,在您的示例中,您需要释放addrport - codenamezero

5
这样怎么样呢:
char buf[BUFSIZE+1];
snprintf(buf,BUFSIZE,"%s",optarg);

或者更完整的示例:

#include <stdio.h>
#include <unistd.h>

#define BUFSIZE 16

int main( int argc, char **argv )
{
    char c;
    char port[BUFSIZE+1];
    char addr[BUFSIZE+1];

    while(( c = getopt( argc, argv, "i:p:" )) != -1 )
        switch ( c )
        {
            case 'i':
                snprintf( addr, BUFSIZE, "%s", optarg );
                break;
            case 'p':
                snprintf( port, BUFSIZE, "%s", optarg );
                break;
            case '?':
                fprintf( stderr, "Unrecognized option!\n" );
                break;
        }

    return 0;
}

如需更多信息,请参阅Getopt文档。


2
使用strdup的答案是解决这个问题的更好方案。它避免了为未知长度的字符串创建固定大小的缓冲区。 - tvanfosson

3

这是getopt文档中的一个缺陷之一:它没有清楚地说明必须复制optarg以供后续使用(例如使用strdup()),因为它可能会被后续选项覆盖或仅由getopt释放。


9
通常不需要复制optarg字符串,因为它是指向原始argv数组的指针,而不是指向可能被覆盖的静态区域的指针。 - dmityugov
@dmityugov - 这可能是真的,但我通常不赞成利用实现内部知识的解决方案。通过将字符串复制到程序员控制下而不是库控制下,可以以很小的代价使代码更加健壮。 - tvanfosson
1
指向 argv 的指针不安全,因为“默认情况下,在扫描 argv 时会对其内容进行排列,以便最终所有非选项都在末尾”,这意味着随着重复调用选项,argv 的内容会发生变化。如果在 options 第一次返回时所有排列都已完成,则文档应该说明如此。 - Urhixidur
@nos 指向字符串的指针可能不会改变,但是 argv 数组中的值会改变,这通常不是人们所期望的。 - Urhixidur
@Urhixidur 我仍然不同意,如果optarg是argv数组中元素的指针,则其类型应为char **,但它是char *。可证明optarg指向argv元素指向的字符串之一。(这些字符串再次存储在glibc中的连续内存块中,我怀疑这个连续的char数组就是那些glibc文档所指的“原始argv数组”,它并不指代main()的参数数组中的指针数组) - nos
显示剩余5条评论

2

对于IP和端口,您无需存储字符串。只需解析它们并将值存储在sockaddr中即可。

#include <arpa/inet.h>                  // for inet_ntop, inet_pton                                                                                                                                                                                                                                                                                                          
#include <getopt.h>                     // for getopt, optarg                                                                                                                                                                                                                                                                                                                
#include <netinet/in.h>                 // for sockaddr_in, etc                                                                                                                                                                                                                                                                                                              
#include <stdio.h>                      // for fprintf, printf, stderr                                                                                                                                                                                                                                                                                                       
#include <stdlib.h>                     // for atoi, EXIT_SUCCESS                                                                                                                                                                                                                                                                                                            
#include <string.h>                     // for memset                                                                                                                                                                                                                                                                                                                        
#include <sys/socket.h>                 // for AF_INET                                                                                                                                                                                                                                                                                                                       

int main(int argc, char *argv[])                                                                                                                                                                                                                                                                                                                                             
{                                                                                                                                                                                                                                                                                                                                                                            
    struct sockaddr_in sa;                                                                                                                                                                                                                                                                                                                                                   
    char c;                                                                                                                                                                                                                                                                                                                                                                  

    memset(&sa, 0, sizeof(sa));                                                                                                                                                                                                                                                                                                                                              
    sa.sin_family = AF_INET;                                                                                                                                                                                                                                                                                                                                                 
    sa.sin_addr.s_addr = htonl(INADDR_ANY);                                                                                                                                                                                                                                                                                                                                         
    sa.sin_port = 0;                                                                                                                                                                                                                                                                                                                                                         

    while ((c = getopt(argc, argv, "i:p:")) != -1)                                                                                                                                                                                                                                                                                                                           
    {                                                                                                                                                                                                                                                                                                                                                                        
        switch (c)                                                                                                                                                                                                                                                                                                                                                           
        {                                                                                                                                                                                                                                                                                                                                                                    
            case 'p':                                                                                                                                                                                                                                                                                                                                                        
                sa.sin_port = htons(atoi(optarg));                                                                                                                                                                                                                                                                                                                           
                break;                                                                                                                                                                                                                                                                                                                                                       
            case 'i':                                                                                                                                                                                                                                                                                                                                                        
                inet_pton(AF_INET, optarg, &(sa.sin_addr));                                                                                                                                                                                                                                                                                                                  
                break;                                                                                                                                                                                                                                                                                                                                                       
            case '?':                                                                                                                                                                                                                                                                                                                                                        
                fprintf(stderr, "Unknown option\n");                                                                                                                                                                                                                                                                                                                         
                break;                                                                                                                                                                                                                                                                                                                                                       
        } /* -----  end switch  ----- */                                                                                                                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                                                                                                                                                        

    char str[INET_ADDRSTRLEN];                                                                                                                                                                                                                                                                                                                                               
    inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN);                                                                                                                                                                                                                                                                                                                
    printf("%s:%d\n", str, ntohs(sa.sin_port));                                                                                                                                                                                                                                                                                                                              

    return EXIT_SUCCESS;                                                                                                                                                                                                                                                                                                                                                     
} /* ----------  end of function main  ---------- */                                            

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