5

Cで同等のバージョンの perl のchomp()関数を実装しようとしていますが、引数として渡された文字列リテラルがセグメンテーション違反を引き起こすコーナー ケースに遭遇しました (当然のことです)。

chomp("some literal string\n");

C99 には、関数に文字列リテラルが渡されたかどうかを検出するための定義済みの方法があり、returnNUL を試行せずに実行できますか?

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 は、呼び出し元のために物事をごまかそうとするべきではありません。後で壊れてしまうだけです。発信者が規則に違反した場合は、その場で見つける必要があります。

呼び出し元が、変更可能な文字列を期待する関数に変更不可能な文字列を渡すと、segfaultが発生するはずです。それ以外はデザインが悪い。

(補遺: もちろん、最良の設計は、呼び出し元が解放する責任がある文字列のコピーを返すことです。)

于 2010-02-23T23:47:41.100 に答える
3

理想chomp的には、新しい文字列を作成して返す必要があります。文字列リテラルが渡されたかどうかを判断する方法はありません。実際、次の署名を使用することをお勧めしますchomp

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

または、2 つの異なる関数を作成し、クライアント用に文書化することもできます。chomp非リテラルとchomplリテラル文字列に使用します。

于 2010-02-23T23:47:33.113 に答える
1

非常に危険/悪い方法が 1 つあります => 通常、文字列リテラルは読み取り専用のデータ セクションに格納されます。したがって、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 に答える