programing

값을 이미 반환하는 경우 함수에서 오류를 반환하는 가장 좋은 방법은 무엇입니까?

sourcejob 2023. 9. 11. 21:37
반응형

값을 이미 반환하는 경우 함수에서 오류를 반환하는 가장 좋은 방법은 무엇입니까?

C에 문자열을 정수로 변환하고 정수를 반환하는 함수를 작성했습니다.함수를 호출할 때 문자열이 유효한 번호가 아닌지도 알려주셨으면 합니다.예전에는 문자열을 음수로 변환할 필요가 없었기 때문에 이 오류가 발생했을 때 -1을 반환했습니다.그런데 지금은 문자열을 음수로 변환했으면 좋겠는데, 오류를 보고하는 가장 좋은 방법은 무엇인가요?

내가 이 일에 대해 확신하지 못했을 경우를 대비해서:이 함수가 오류를 사용자에게 보고하는 것이 아니라, 함수를 호출한 코드에 오류를 보고하는 것입니다. ("보고"가 잘못된 단어일 수도 있습니다...)

코드는 다음과 같습니다.

s32 intval(const char *string) {
    bool negative = false;
    u32 current_char = 0;

    if (string[0] == '-') {
        negative = true;
        current_char = 1;
    }

    s32 num = 0;
    while (string[current_char]) {
        if (string[current_char] < '0' || string[current_char] > '9') {
            // Return an error here.. but how?
        }

        num *= 10;
        num += string[current_char] - '0';
        current_char++;
    }

    if (negative) {
        num = -num;
    }

    return num;
}

여러 가지 방법이 있습니다.모두 장단점이 있습니다.

  • 함수가 오류 코드를 반환하도록 하고 포인터를 위치로 전달하여 결과를 반환합니다.이것의 좋은 점은 결과에 과부하가 걸리지 않는다는 것입니다.나쁜 점은 함수의 실제 결과를 표현식에 직접 사용할 수 없다는 것입니다.

    Evan Teran은 성공 변수(발신자가 상관하지 않을 경우 선택적으로 NULL이 될 수 있음)에 대한 포인터를 호출자에게 전달하고 함수에서 실제 값을 반환하는 변형을 제안했습니다.이를 통해 호출자가 오류 결과의 기본값으로 정상이거나 함수가 실패할 수 없음을 알고 있을 때 함수를 식에 직접 사용할 수 있는 장점이 있습니다.

  • 값이가 될 수 ) '' 하여 을 를 일 한 이 를 한 INT_MAX아니면INT_MIN좋은 가치가 그렇게 극단적일 수 없다면 말입니다. 더 :로더한류를기해능른예(능른예해:sso로(hrmnlo더기naGetLastError()) 자문이 합니다. ( 에 이 합니다 합니다 이 :errno반품 값이 잘못된 값이 없을 때는 잘 작동하지 않으며, 많은 사람들이 일반적으로 나쁜 형태로 간주합니다.

    이 기법을 사용하는 함수의 예로는 getc()가 있는데, 파일의 끝에 도달하거나 오류가 발생하면 EOF를 반환합니다.

  • 함수가 오류 표시를 직접 반환하지 않고 호출자가 다른 함수나 전역을 쿼리하도록 합니다.는 V의"다와합니다와 합니다.On Error Goto Next작동합니다. 그것은."라고 말했습니다. 그리고 그것은 거의 보편적으로 나쁜 방법으로 여겨집니다.

  • 하지만 또 다른 방법은 '기본값' 값을 갖는 것입니다.를 들면,를은.atoi()당신의 기능과 거의 같은 기능을 가지고 있는 기능.intval()함수는 문자를 변환할 수 없을 때 0을 반환합니다(문자가 문자열 끝에 도달할 때까지 변환할 문자 또는 숫자가 아닌 문자를 소비한다는 점에서 사용자의 함수와 다릅니다.

    가 서 되었는지 입니다 이 은 하는 이 되었는지 으로 가 입니다 서 은 atoi().

    저는 오류를 다루는 이런 방식을 별로 좋아하지 않습니다.

다른 옵션이 생각나면 업데이트하겠습니다.

뭐, 그런 식으로.NET은 Int32에서 이를 처리합니다.TryParse는 성공/실패를 반환하고 구문 분석된 값을 pass-by-reference 매개 변수로 다시 전달합니다.C에서도 동일하게 적용될 수 있습니다.

int intval(const char *string, s32 *parsed)
{
    *parsed = 0; // So that if we return an error, the value is well-defined

    // Normal code, returning error codes if necessary
    // ...

    *parsed = num;
    return SUCCESS; // Or whatever
}

일반적인 방법은 다음과 같이 성공 플래그에 포인터를 전달하는 것입니다.

int my_function(int *ok) {
    /* whatever */
    if(ok) {
        *ok = success;
    }
    return ret_val;
}

이렇게 부릅니다.

int ok;
int ret = my_function(&ok);
if(ok) {
    /* use ret safely here */
}

EDIT: 구현 예:

s32 intval(const char *string, int *ok) {
    bool negative = false;
    u32 current_char = 0;

    if (string[0] == '-') {
        negative = true;
        current_char = 1;
    }

    s32 num = 0;
    while (string[current_char]) {
        if (string[current_char] < '0' || string[current_char] > '9') {
                // Return an error here.. but how?
                if(ok) { *ok = 0; }
        }

        num *= 10;
        num += string[current_char] - '0';
        current_char++;
    }

    if (negative) {
        num = -num;
    }
    if(ok) { *ok = 1; }
    return num;
}

int ok;
s32 val = intval("123a", &ok);
if(ok) {
    printf("conversion successful\n");
}

os-style global errno도다가다es도 사용errno.h.

errno가 0이 아니면 문제가 생긴 것입니다.

여기 오류에 대한 맨페이지 참조가 있습니다.

표준 라이브러리가 이 문제를 어떻게 처리하는지 살펴봅니다.

long  strtol(const  char  * restrict str,  char **restrict endptr, int base);

여기서 호출 후 endptr은 구문 분석할 수 없는 첫 번째 문자를 가리킵니다.endptr == str인 경우 문자가 변환되지 않아 문제가 발생합니다.

일반적으로 저는 존 스키트가 제안한 방식을 선호합니다. 즉, 성공에 대한 부울(intor utin)을 반환하고 그 결과를 통과된 주소에 저장하는 것입니다.하지만 귀사의 기능은 strtol과 매우 유사하므로 귀사의 기능에 동일한(또는 유사한) API를 사용하는 것이 좋다고 생각합니다.my_strtos32와 유사한 이름을 지정하면 설명서를 읽지 않아도 함수가 수행하는 작업을 쉽게 이해할 수 있습니다.

편집: 기능이 명시적으로 10 기반이므로 my_strtos32_base10이 더 나은 이름입니다.사용자의 기능이 어려운 상황이 아니라면 구현을 생략합니다.그리고 간단히 strtol을 둘러 싸면 됩니다.


s32
my_strtos32_base10(const char *nptr, char **endptr)
{
    long ret;
    ret = strtol(nptr, endptr, 10);
    return ret;
}

나중에 병목 현상으로 인식하게 되더라도 고객의 요구에 맞게 최적화할 수 있습니다.

속성이 관심 있는 값이 되고 다른 속성이 상태 플래그가 되는 클래스의 인스턴스를 반환할 수 있습니다.또는 결과 클래스의 인스턴스를 통과합니다.

Pseudo code
  MyErrStatEnum = (myUndefined, myOK, myNegativeVal, myWhatever)

ResultClass
  Value:Integer;
  ErrorStatus:MyErrStatEnum

예 1:

result := yourMethod(inputString)

if Result.ErrorStatus = myOK then 
   use Result.Value
else
  do something with Result.ErrorStatus

free result

예제2

create result
yourMethod(inputString, result)

if Result.ErrorStatus = myOK then 
   use Result.Value
else
  do something with Result.ErrorStatus

free result

이 접근 방식의 장점은 결과 클래스에 추가 속성을 추가하여 언제든지 돌아오는 정보를 확장할 수 있다는 것입니다.

이 개념을 더 확장하기 위해 입력 매개변수가 여러 개인 메서드 호출에도 적용됩니다.예를 들어 CallYourMethod(val1, val2, val3, boool1, boool2, string1) 대신 val1, val2, val3, boool1, boool2, string1과 일치하는 속성을 가진 클래스를 사용하고 이를 단일 입력 매개 변수로 사용합니다.메소드 호출을 정리하고 향후 코드를 보다 쉽게 수정할 수 있습니다.매개 변수가 몇 개 이상인 메서드 호출은 사용/디버깅하기가 훨씬 어렵다는 것을 보셨을 것입니다.(7이 제가 말할 수 있는 가장 확실한 것입니다.

값을 이미 반환하는 경우 함수에서 오류를 반환하는 가장 좋은 방법은 무엇입니까?

다양한 답변에 대한 몇 가지 추가적인 생각.


구조물 반환

코드는 값과 오류 코드를 반환할 수 있습니다.관심사는 유형의 확산입니다.

typedef struct {
  int value;
  int error;
} int_error;

int_error intval(const char *string);

...

int_error = intval(some_string);
if (int_error.error) {
  Process_Error();
}

int only_care_about_value = intval(some_string).value;
int only_care_about_error = intval(some_string).error;

숫자가 아닌 것과NULL

함수 반환 유형이 값을 제공할 때 특수 값을 사용합니다.
C에서는 숫자가 아닌 숫자가 필요합니다.

#include <math.h>
#include <stddef.h>

double y = foo(x);
if (isnan(y)) {
  Process_Error();
}

void *ptr = bar(x);
if (ptr == NULL) {
  Process_Error();
}

_Generic/기능 과부하

의 장단점을 고려할 때error_t foo(&dest, x)대.dest_t foo(x, &error),

단계적으로 사용할 경우_Generic또는 컴파일러 확장자로 오버로드되는 함수, 2가지 이상의 유형을 선택하면 반환 값이 아닌 호출의 매개 변수를 기반으로 호출되는 기본 함수를 구별하는 것이 타당합니다.일반적인 유형인 오류 상태를 반환합니다.

예제: 함수error_t narrow(destination_t *, source_t)하나의 유형의 값을 더 좁은 유형으로 변환시킨 것처럼.long long로.short소스 값이 대상 유형의 범위에 있는지 여부를 테스트했습니다.

long long ll = ...; 
int i;
char ch; 
error = narrow(&i, ll);
...
error = narrow(&ch, i);

언급URL : https://stackoverflow.com/questions/291828/what-is-the-best-way-to-return-an-error-from-a-function-when-im-already-returni

반응형