我正在尝试在C中实现perl的chomp()
函数的eqivilent版本,并且我遇到了一个角落案例,其中作为参数传递的字符串文字将导致分段错误(理所当然)。
示例chomp("some literal string\n");
在C99中是否有一个定义的方法来检测我的函数是否传递了一个字符串文字,以便我可以return
而不试图将其删除?
char* chomp(char *s)
{
char *temp = s;
if (s && *s)
{
s += strlen(s) - 1;
if (*s == '\n')
{
*s = '\0';
}
}
return temp;
}
答案 0 :(得分:5)
在C99中是否有一个定义的方法来检测我的函数是否传递了一个字符串文字以便我可以返回而不试图将其移出?
你不应该。
你的API不应该试图为调用者捏造东西,只是让它稍后破坏。 如果来电者违反了规则,那么他们应该在那里找到。
如果调用者将非可变字符串传递给期望可变字符串的函数,则应该段错误。还有其他不好的设计。
(附录:当然,最好的设计是返回调用者负责释放的字符串副本。)
答案 1 :(得分:3)
理想情况下,chomp
应该创建一个新字符串并将其返回。无法确定您是否传递了字符串文字。事实上,我建议对chomp
使用以下签名:
char *chomp(const char *s); /* do not modify input parameters */
或者,您可以创建两个不同的函数并为客户端记录它们:对非文字使用chomp
,对文字字符串使用chompl
。
答案 2 :(得分:1)
有一种非常危险/坏的方式=>通常字符串文字存储在只读数据部分中。因此,一种方法是尝试写入目标字符串 - 如果segmentation fault
收到signal callback
- 那么这意味着您的字符串是文字的,并返回到longjmp
的测试函数。
类似的东西:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
static jmp_buf jbuf;
static void catch_segv() {
longjmp(jbuf, 1);
}
int isLiteral(char * ptr) {
if (setjmp(jbuf) == 0)
return (*ptr = *ptr, 0);
else
return 1;
}
int main()
{
char writableString[] = "some writable string";
signal(SIGSEGV, catch_segv);
printf("is literal = %d\n", isLiteral(writableString));
printf("is literal = %d\n", isLiteral("read-only string"));
return 0;
}
但鉴于在SIGSEGV
之后恢复程序是非常危险的事情并且鉴于字符串文字并不总是存储在只读数据部分 - 这种解决方案非常不推荐用于生产。