我如何 return 来自一个函数的字符串,该函数将在 C 中的 printf 中使用?
How do I return a string from a function that's meant to be used in printf in C?
我的函数需要 return 一个字符串并使用索引构建它。理想情况下,我想在 printf() 中使用 return 值。我知道鉴于我的 return 类型,我需要 return 一个 char 字符串指针,但我不能使 reg 成为一个字符串指针,因为我需要访问单个元素。另外,我知道我需要 malloc() 它,但我不知道如果它被用作 printf 的参数我将如何释放该内存。
这是我的代码:
char * printRegister(int num) {
char reg[] = "$error";
memset(reg, 0, sizeof(reg));
switch(num)
{
case 0:
strcpy(reg, "$zero");
break;
case 1:
strcpy(reg, "$at");
break;
case 2:
case 3:
reg[0] = '$';
reg[1] = 'v';
reg[2] = num - 2 + '0';
reg[3] = '[=11=]';
break;
case 4:
case 5:
case 6:
case 7:
reg[0] = '$';
reg[1] = 'a';
reg[2] = num - 4 + '0';
reg[3] = '[=11=]';
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
reg[0] = '$';
reg[1] = 't';
reg[2] = num - 8 + '0';
reg[3] = '[=11=]';
break;
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
reg[0] = '$';
reg[1] = 's';
reg[2] = num - 16 + '0';
reg[3] = '[=11=]';
break;
case 24:
case 25:
reg[0] = '$';
reg[1] = 't';
reg[2] = num - 16 + '0';
reg[3] = '[=11=]';
break;
case 26:
case 27:
reg[0] = '$';
reg[1] = 'k';
reg[2] = num - 26 + '0';
reg[3] = '[=11=]';
break;
case 28:
strcpy(reg, "$gp");
break;
case 29:
strcpy(reg, "$sp");
break;
case 30:
strcpy(reg, "$fp");
break;
case 31:
strcpy(reg, "$ra");
break;
default:
strcpy(reg, "error");
break;
}
return reg;
}
有办法吗?
How do I return a string from a function that's meant to be used in printf in C?
对于 C99 或更高版本,使用 复合文字 来临时存储字符串。
首先,重写 printRegister()
以接受 char *
缓冲区。
#define printRegister_N 7
// char * printRegister(int num) {
char * printRegister(char *reg, int num) {
// char reg[] = "$error";
// memset(reg, 0, sizeof(reg));
memset(reg, 0, printRegister_N); // not really needed anymore with compound literal
...
return reg;
}
形成一个调用 printRegister()
和 复合文字 的宏。
// v---------------------------v compound literal
#define PRINT_REG(num) printRegister((char [printRegister_N]){ 0 }, (num))
然后调用PRINT_REG(num)
。返回的 char*
(它是指向 复合文字 的指针)在块结束之前有效。不需要 *alloc()
、free()
。
printf("1st:%s 2nd:%s\n", PRINT_REG(0), PRINT_REG(1));
代码仍然使用 "%s"
的常用装饰,例如 "%-7s"
、"%.*s"
等
试试 strdup(),它会为您分配内存并复制您想要的任何字符串。
任何已经 dynamically allocated 的内存块都可以用 free() 释放。
举个例子:
#include <string.h> //note: don't include "string", instead include string.h
#include <stdlib.h> //note: this header defines free,
int main()
{
char *data = strdup("the return value of strdup is will be a string containing this");
/* use dynamically allocated string... */
free(data); /* free up the memory. */
}
通过声明一个接受字符串参数的辅助函数
void myprint(char *str) {
printf("rs: %s\n", str);
}
您可以将 printRegister()
的实现更改为
void printRegister(int num, void (*fn)(char*)) {
...
fn(reg); // instead of return reg;
}
然后调用
printRegister(rs, myprint);
这通过调换调用者和被调用者的角色来避免动态分配内存的需要; printRegister()
的调用者现在提供了一个 callback 可以接受临时堆栈变量并对它做一些事情。
当前代码具有未定义的行为,因为您 return 指向具有自动存储功能的对象的指针,当函数 returns.
时,该对象将超出范围
有几种方法可以解决这个问题:
你可以给 reg
static
存储空间 class。返回指向 reg
的指针是可以的,但是内容将被随后对 printRegister
的调用覆盖,因此您不能多次使用 printRegister
作为单个 printf
调用的参数.
您可以 return reg
的已分配副本,但调用者需要释放此内存块以避免内存泄漏。这对您的目的来说很麻烦。
您可以更改 printRegister
的原型以获取指向目标数组的指针,并且 return 在存储寄存器名称的文本表示之后。请注意,在同一 printf
调用中多次调用 printRegister
需要单独的数组。
因为只有 33 种不同的可能字符串,您可以 return 字符串常量。此解决方案简单高效,但建议将 return 类型更改为 const char *
.
这是最后一种方法的实现:
const char *printRegister(int num) {
static const char * const regname[] = {
"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
"$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
};
return (num >= 0 && num < 32) ? regname[num] : "error";
}
我的函数需要 return 一个字符串并使用索引构建它。理想情况下,我想在 printf() 中使用 return 值。我知道鉴于我的 return 类型,我需要 return 一个 char 字符串指针,但我不能使 reg 成为一个字符串指针,因为我需要访问单个元素。另外,我知道我需要 malloc() 它,但我不知道如果它被用作 printf 的参数我将如何释放该内存。
这是我的代码:
char * printRegister(int num) {
char reg[] = "$error";
memset(reg, 0, sizeof(reg));
switch(num)
{
case 0:
strcpy(reg, "$zero");
break;
case 1:
strcpy(reg, "$at");
break;
case 2:
case 3:
reg[0] = '$';
reg[1] = 'v';
reg[2] = num - 2 + '0';
reg[3] = '[=11=]';
break;
case 4:
case 5:
case 6:
case 7:
reg[0] = '$';
reg[1] = 'a';
reg[2] = num - 4 + '0';
reg[3] = '[=11=]';
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
reg[0] = '$';
reg[1] = 't';
reg[2] = num - 8 + '0';
reg[3] = '[=11=]';
break;
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
reg[0] = '$';
reg[1] = 's';
reg[2] = num - 16 + '0';
reg[3] = '[=11=]';
break;
case 24:
case 25:
reg[0] = '$';
reg[1] = 't';
reg[2] = num - 16 + '0';
reg[3] = '[=11=]';
break;
case 26:
case 27:
reg[0] = '$';
reg[1] = 'k';
reg[2] = num - 26 + '0';
reg[3] = '[=11=]';
break;
case 28:
strcpy(reg, "$gp");
break;
case 29:
strcpy(reg, "$sp");
break;
case 30:
strcpy(reg, "$fp");
break;
case 31:
strcpy(reg, "$ra");
break;
default:
strcpy(reg, "error");
break;
}
return reg;
}
有办法吗?
How do I return a string from a function that's meant to be used in printf in C?
对于 C99 或更高版本,使用 复合文字 来临时存储字符串。
首先,重写 printRegister()
以接受 char *
缓冲区。
#define printRegister_N 7
// char * printRegister(int num) {
char * printRegister(char *reg, int num) {
// char reg[] = "$error";
// memset(reg, 0, sizeof(reg));
memset(reg, 0, printRegister_N); // not really needed anymore with compound literal
...
return reg;
}
形成一个调用 printRegister()
和 复合文字 的宏。
// v---------------------------v compound literal
#define PRINT_REG(num) printRegister((char [printRegister_N]){ 0 }, (num))
然后调用PRINT_REG(num)
。返回的 char*
(它是指向 复合文字 的指针)在块结束之前有效。不需要 *alloc()
、free()
。
printf("1st:%s 2nd:%s\n", PRINT_REG(0), PRINT_REG(1));
代码仍然使用 "%s"
的常用装饰,例如 "%-7s"
、"%.*s"
等
试试 strdup(),它会为您分配内存并复制您想要的任何字符串。
任何已经 dynamically allocated 的内存块都可以用 free() 释放。
举个例子:
#include <string.h> //note: don't include "string", instead include string.h
#include <stdlib.h> //note: this header defines free,
int main()
{
char *data = strdup("the return value of strdup is will be a string containing this");
/* use dynamically allocated string... */
free(data); /* free up the memory. */
}
通过声明一个接受字符串参数的辅助函数
void myprint(char *str) {
printf("rs: %s\n", str);
}
您可以将 printRegister()
的实现更改为
void printRegister(int num, void (*fn)(char*)) {
...
fn(reg); // instead of return reg;
}
然后调用
printRegister(rs, myprint);
这通过调换调用者和被调用者的角色来避免动态分配内存的需要; printRegister()
的调用者现在提供了一个 callback 可以接受临时堆栈变量并对它做一些事情。
当前代码具有未定义的行为,因为您 return 指向具有自动存储功能的对象的指针,当函数 returns.
时,该对象将超出范围有几种方法可以解决这个问题:
你可以给
reg
static
存储空间 class。返回指向reg
的指针是可以的,但是内容将被随后对printRegister
的调用覆盖,因此您不能多次使用printRegister
作为单个printf
调用的参数.您可以 return
reg
的已分配副本,但调用者需要释放此内存块以避免内存泄漏。这对您的目的来说很麻烦。您可以更改
printRegister
的原型以获取指向目标数组的指针,并且 return 在存储寄存器名称的文本表示之后。请注意,在同一printf
调用中多次调用printRegister
需要单独的数组。因为只有 33 种不同的可能字符串,您可以 return 字符串常量。此解决方案简单高效,但建议将 return 类型更改为
const char *
.
这是最后一种方法的实现:
const char *printRegister(int num) {
static const char * const regname[] = {
"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
"$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
};
return (num >= 0 && num < 32) ? regname[num] : "error";
}