在C中生成路径的最佳方法是什么?

时间:2013-06-17 16:09:58

标签: c string macros c-preprocessor

我需要在运行时生成三种不同类型的路径:

  1. / SYS /类/ GPIO / GPIO%d
  2. / SYS /类/ GPIO / GPIO%d /值
  3. / SYS /类/ GPIO / GPIO%d /方向
  4. 目前我通过执行以下操作来生成这些:

    #define GPIO_PATH_BASE "/sys/class/gpio/gpio"
    #define GPIO_PATH_DIRECTION "/direction"
    #define GPIO_PATH_VALUE "/value"
    
    int open_gpio(const char * port) {
        char * base_path = (char *) malloc(sizeof(GPIO_PATH_BASE) + sizeof(port));
        strcpy(base_path, GPIO_PATH_BASE);
        strcat(base_path, port);
    
        char * value_path = (char *) malloc(sizeof(base_path) + sizeof(GPIO_PATH_VALUE));
        strcpy(value_path, (const char *) base_path);
        strcat(value_path, GPIO_PATH_VALUE);
    
        char * dir_path = (char *) malloc(sizeof(base_path) + sizeof(GPIO_PATH_DIRECTION));
        strcpy(dir_path, (const char *) base_path);
        strcat(dir_path, GPIO_PATH_DIRECTION);
    }
    

    我实际上对这种方法很不满意。是否有可能让宏给我这个东西或者我应该创建一个辅助函数?

    博多

4 个答案:

答案 0 :(得分:4)

我发现@larsmans提到的sprintf(或snprintf更适合字符串操作,特别是如果你想在字符串中添加小数值。

我会使用PATH_MAX(在limits.h中定义)来获得静态分配的缓冲区,如:

#include <limits.h>
#include <stdio.h>

unsigned char path[PATH_MAX];

#define GPIO_PATH_BASE "/sys/class/gpio/gpio"
#define GPIO_PATH_VALUE "/value"

int main(void)
{
        snprintf(path, PATH_MAX, "%s/%d%s", GPIO_PATH_BASE, 42, GPIO_PATH_VALUE);
        puts(path);
        return 0;
}

$ make main
cc     main.c   -o main
$ ./main 
/sys/class/gpio/gpio/42/value
$

答案 1 :(得分:4)

您可以创建一个包含两部分的函数,分配空间并连接它们。这应该减少代码重复,同时保持代码可读:

static char *concat(const char* prefix, const char* suffix) {
    size_t len = strlen(prefix) + strlen(suffix) + 1;
    char *res = malloc(len);
    strcpy(res, prefix);
    strcat(res, suffix);
    return res;
}

现在您可以按如下方式使用此功能:

char * base_path = concat(GPIO_PATH_BASE, port);
char * value_path = concat(base_path, GPIO_PATH_VALUE);
char * dir_path = concat(base_path, GPIO_PATH_DIRECTION);

答案 2 :(得分:2)

我非常喜欢使用sprintf来生成这样的字符串。但这假设您有一个合理的最大尺寸,您知道不会超过。

当然,这至少比sizeof(base_path)好一点,这是完全错误的。

对于在模块外部不可见的变量,使用malloc似乎也是一个坏主意。

如果我们假设port是正确的字符串,可以这样:

 char base_path[100]; 

 sprintf(base_path, "%s/%s", GPIO_PATH_BASE, port); 

答案 3 :(得分:2)

如果您的系统支持它,那么asprintf()是最简单的机制:

#define GPIO_PATH_BASE      "/sys/class/gpio/gpio"
#define GPIO_PATH_DIRECTION "/direction"
#define GPIO_PATH_VALUE     "/value"

int open_gpio(const char * port)
{
    char *base_path  = asprintf("%s%s", GPIO_PATH_BASE, port);
    char *value_path = asprintf("%s%s", base_path, GPIO_PATH_VALUE);
    char *dir_path   = asprintf("%s%s", base_path, GPIO_PATH_DIRECTION);
    //...do some work with these...or return them...
    //...should check for failed allocations, too...
}

如果您的系统不支持asprintf(),您可以通过以下方式“伪造”它:

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

/* Should be in a header */
#ifndef HAVE_ASPRINTF
extern int asprintf(char **ret, const char *format, ...);
extern int vasprintf(char **ret, const char *format, va_list args);
#endif

#ifndef HAVE_ASPRINTF

int vasprintf(char **ret, const char *format, va_list args)
{
    va_list copy;
    va_copy(copy, args);

    /* Make sure return pointer is determinate */
    *ret = 0;

    int count = vsnprintf(NULL, 0, format, args);
    if (count >= 0)
    {
        char* buffer = malloc(count + 1);
        if (buffer != NULL)
        {
            count = vsnprintf(buffer, count + 1, format, copy);
            if (count < 0)
            {
                free(buffer);
                buffer = 0;
            }
            *ret = buffer;
        }
    }

    va_end(copy);

    return count;
}

int asprintf(char **ret, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    int count = vasprintf(ret, format, args);
    va_end(args);
    return(count);
}

#endif /* HAVE_ASPRINTF */