3

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

  1. /sys/class/gpio/gpio%d
  2. /sys/class/gpio/gpio%d/值
  3. /sys/class/gpio/gpio%d/方向

目前我通过执行以下操作生成这些:

#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

4 回答 4

4

我发现sprintf(或@larsmans 提到的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
$
于 2013-06-17T16:14:49.650 回答
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);
于 2013-06-17T16:20:47.333 回答
2

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

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

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

如果我们假设这port是正确的字符串,如下所示:

 char base_path[100]; 

 sprintf(base_path, "%s/%s", GPIO_PATH_BASE, port); 
于 2013-06-17T16:16:55.573 回答
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 */
于 2013-06-17T16:22:10.257 回答