5

我正在尝试chomp()在 C 中实现 perl 函数的等效版本,我遇到了一个极端情况,其中作为参数传递的字符串文字将导致分段错误(理所当然)。

例子chomp("some literal string\n");

C99 中是否有定义的方法来检测我的函数是否传递了字符串文字,这样我就可以return不尝试将其 NUL 出来?

char* chomp(char *s)
{
    char *temp = s;

    if (s && *s)
    {
        s += strlen(s) - 1;
        if (*s == '\n')
        {
            *s = '\0';
        }
    }
    return temp;
}
4

3 回答 3

5

C99 中是否有定义的方法来检测我的函数是否传递了字符串文字,以便我可以返回而不尝试将其 NUL 出来?

你不应该。

你的 API 不应该试图为调用者捏造东西,只是让它在以后中断。如果来电者违反了规则,他们应该立即发现。

如果调用者将非可变字符串传递给期望可变字符串的函数,则它应该出现段错误。其他任何东西都是糟糕的设计。

(附录:当然,最好的设计是返回调用者负责释放的字符串的副本。)

于 2010-02-23T23:47:41.100 回答
3

理想情况下,您chomp应该创建一个新字符串并返回它。无法确定您是否传递了字符串文字。事实上,我建议使用以下签名chomp

char *chomp(const char *s); /* do not modify input parameters */

或者,您可以创建两个不同的函数并为客户端记录它们:chomp用于非文字和chompl文字字符串。

于 2010-02-23T23:47:33.113 回答
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是非常危险的事情,并且考虑到字符串文字并不总是存储在只读数据部分 - 这个解决方案非常不推荐用于生产。

于 2012-04-20T13:41:02.330 回答