2017-11-14 1 views
4

누군가가 우리 C++ 응용 프로그램에 함수를 작성했으며 이미 프로덕션에 포함되어 있으며 아직 응용 프로그램을 손상시키지 않는 이유를 알지 못합니다. 아래는 코드입니다. C++ 응용 프로그램의 정적 데이터 메모리 제한

char *str_Modify() 
{ 
    char buffer[70000] = { 0 }; 
    char targetString[70000] = { 0 }; 

    memset(targetString, '\0', sizeof(targetString)); 

    ... 
    ... 
    ... 
    return targetString; 
} 

당신이 볼 수 있듯이

는,이 함수는 지역 변수의 주소를 반환하고 할당 된 메모리는 함수가 반환되면 해제됩니다. 내 질문

  • 정적 데이터 메모리 한도 란 무엇입니까?
  • 이 코드의 빠른 수정은 무엇입니까? 변수 targetString을 정적으로 만드는 것이 좋은 습관입니까?
+0

이 C 또는 C++입니까? 어떤 추가 제약이 있습니까? – hyde

+1

정적이라면 코드 위의 굵은 주석과 h 파일의 모든 서명 : '문장이 안전하지 않음 - 여러 줄에서 소리내어 말하기'를 추가하십시오. Altrnatives는 공간을 할당하거나 호출자에게 버퍼를 제공하게하는 데, 둘 다 호출 코드를 변경해야합니다. –

+2

오 - 원 저작자가 더 이상 귀사에 적합하지 않게하십시오. –

답변

6

(memset에 전화가 아무런 영향을주지 않습니다, 모든 요소는 통화에 앞서 제로 초기화됩니다.) 그것은의 정의되지 않은 동작의 한 표현 때문에 응용 프로그램 충돌 아니에요

당신의 코드 (자동 저장 기간으로 현재 범위를 벗어난 변수에 대한 포인터를 반환 함)로 인해 응용 프로그램이 충돌하지 않습니다.

예,이를 static으로 지정하면 포인터의 유효성을 검사하지만 동시 액세스를 중심으로 다른 문제가 발생할 수 있습니다.

그리고 언어 선택 : C++에는 다른 기술이 있습니다.

+2

개인적으로 UB의 최악의 현상이라고 생각합니다. – StoryTeller

+1

사실,하지만 OP의 고양이는 다른 날을보기 위해 살고 있습니다. – Bathsheba

1

함수 호출이 끝난 후 정적 변수의 주소가 메모리에 반환되기 때문에은 C 및 C++에서 올바르게 정의 된 동작 입니다. 예를 들어

: 그것은 GCC 컴파일러에 잘 작동

#include <stdio.h> 

int *f() 
{ 
    static int a[10]={0}; 
    return a; 
} 
int main() 
{ 
    f(); 
    return 0; 
} 

.

또한
prog.c: In function 'f': 
prog.c:6:12: warning: function returns address of local variable [-Wreturn-local-addr] 
    return a; 
      ^

question 코멘트 루딘으로 쓴 참조 : 정적 키워드를 제거하는 경우 [Live Demo]

그러나, 다음 컴파일러는 경고를 생성합니다.

다른 이야기 인 과 int* fun (void) { int i = 10; return &i; },을 혼동한다고 생각합니다. 전자는 잘 정의되어 있으며, 후자는 정의되지 않은 동작입니다. 기억해야 할

두 번째 포인트는 당신이 가있을 것이다, 그래서 C는 함수의 외부로 지역 변수의 주소를 반환 옹호하지 않는다는 것입니다 :

또한, tutorialspoint이의 말 로컬 변수를 정적 변수 변수로 정의하십시오.

+0

호출 코드가 반환 값을 사용하지 않으면 UB가 아닙니다. –

1

돌아 오는 targetString은 다른 답변에서 말한 것처럼 실제로 UB입니다.그러나 일부 플랫폼 (특히 포함 된 것들)에서 충돌 할 수있는 보완적인 또 다른 이유가 있습니다. 스택 크기. 자동 변수가 일반적으로 사용되는 스택 세그먼트는 종종 수 킬로바이트로 제한됩니다. 64K가 일반적 일 수 있습니다. 두 개의 70K 어레이는 사용하기에 안전하지 않을 수 있습니다.

만들기 targetString 정적 수정은 두 가지 문제를 모두 해결하며 IMO의 불편한 개선입니다. 코드가 다중 스레드에서 재진입 적으로 사용되면 여전히 문제가 될 수 있습니다. 어떤 경우에는 비효율적 인 기억의 사용으로 간주 될 수도 있습니다.

다른 방법으로 반환 버퍼를 동적으로 할당하고 포인터를 반환하고 더 이상 필요하지 않을 때 호출 코드를 해제 할 수 있습니다.

이 아닌가? 크래시 : 스택 세그먼트가 충분히 크고 다른 함수가 충분히 사용하여 buffer[]을 덮어 쓰고 처음으로 푸시되면; targetString[]은 사용 된 스택 바로 아래에 매달려 상처를 입지 않고 효과적으로 살아남을 수 있습니다. 매우 안전하지 않은!

1

정적 데이터 메모리 한도 란 무엇입니까?

플랫폼에 따라 다릅니다. 플랫폼 (OS, 컴파일러, 버전)을 지정하지 않았으므로 누구도 말할 수 없습니다. 아마 괜찮을거야.

이 코드의 빠른 수정은 무엇입니까?

신속한 수정은 실제로 버퍼를 정적으로 만듭니다.

좋은 수정

char *modify(char *out, size_t outsz) { 
    // ... 
    return out; 
} 

으로서의 기능을 재기록한다 (입력을 반환하면 기존 코드의 새로운 기능을 다시 간단히 단지이다).

변수 targetString을 정적으로 설정하는 것이 좋습니까? ~ 메모리 및/또는 주소 공간의 68KB

  1. 버퍼는 항상 같은 크기이며, 항상 사용 :

번호 때로는 당신이 할 수있는 최선의 방법이지만 문제의 번호를 가지고 아무 이유없이. 어떤 상황에서는 더 큰 것을 사용할 수없고 다른 상황에서는 더 작은 것을 사용할 수 없습니다. 전체적으로 memset을 가지고 있다면 버퍼가 훨씬 더 작을 수있는 상황에서 속도 위반이 발생합니다.

  • static (또는 전역 변수) 변수를 사용하면 재진입이 중단됩니다. 간단한 예 : 두 번째 호출 (이것은 영구 상태를 가지고 있기 때문에, 두 개의 서로 다른 스트링 토큰 화 인터리브하는데 사용될 수있는 strtok 비교) 제를 덮어 쓰기 때문에

    printf("%s,%s\n", str_Modify(1), str_Modify(2)); 
    

    같은 코드가 올바로 수행되지있다.

  • 다중 스레드를 사용하는 경우 재진입이 불가능하므로 스레드로부터 안전하지 않습니다. 그것은 엉망입니다.
  • 관련 문제