开发者

How to detect the passing of a string literal to a function in C?

I am trying to implement an eqivilent version of perl's chomp() function in C and I have come across a corner case where a string literal passed as the argument will cause a segmentation fault (rightfully so).

Example chomp("some literal string\n");

Is there a defined way in C99 to detect wether or not my function was passed a string literal so that I can return without attempting to NUL it out?

char* chomp(char 开发者_StackOverflow中文版*s)
{
    char *temp = s;

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


Is there a defined way in C99 to detect wether or not my function was passed a string literal so that I can return without attempting to NUL it out?

You shouldn't.

Your API shouldn't attempt to fudge things for the caller, only to have it break later on. If the caller breaks the rules, they should find out then and there.

If the caller passes a non-mutable string to a function that expects a mutable one, it should segfault. Anything else is bad design.

(Addendum: The best design, of course, would be to return a copy of the string that the caller is responsible for freeing.)


Your chomp should ideally create a new string and return it. There is no way to determine if you were passed a string literal or not. In fact, I'd suggest using the following signature for chomp:

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

Or, you could create two different functions and document them for the clients: use chomp for non-literals and chompl for literal strings.


There is one VERY risky/bad way => Usually string-literals are stored in read-only data section. So one way is to try to write to destination string - if segmentation fault is received into signal callback - then that means that your string is literal, and return back to test function with longjmp. Something like:

#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;
}

But given that resuming program after SIGSEGV is very risky thing and given that string literals are not always stored on read-only data section - this solution is highly un-recommended for production.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜