我需要在运行时生成三种不同类型的路径:
目前我通过执行以下操作来生成这些:
#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);
}
我实际上对这种方法很不满意。是否有可能让宏给我这个东西或者我应该创建一个辅助函数?
博多
答案 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 */