변수 이름을 공급하지 않고 %d를 인쇄 할 때 printf의 동작

StackOverflow https://stackoverflow.com/questions/437816

  •  22-07-2019
  •  | 
  •  

문제

방금 이상한 문제가 발생했는데 정수 변수를 인쇄하려고하지만 변수 이름을 지정하는 것을 잊었습니다.

printf("%d");

대신에

printf("%d", integerName);

놀랍게도 프로그램은 컴파일되며 출력이 있으며 무작위가 아닙니다. 사실, 그것은 내가 처음에 인쇄하고 싶었던 바로 정수가되었으며, 이것은 M-1입니다.

오류 printf 진술은 프로그램이 계속 실행되는 한 M-1을 일관되게 출력합니다 ... 다시 말해서, 진술이 읽는 것처럼 정확히 작동합니다.

printf("%d", m-1);

이 행동의 이유를 아는 사람이 있습니까? 명령 줄 옵션없이 g ++를 사용하고 있습니다.

#include <iostream>
#define maxN 100
#define ON 1
#define OFF 0

using namespace std;

void clearArray(int* array, int n);
int fillArray(int* array, int m, int n);

int main()
{
    int n = -1, i, m;
    int array[maxN];
    int found;

    scanf("%d", &n);

    while(n!=0)
    {
        found=0;
        m = 1;
        while(found!=1)
        {
            if(m != 2 && m != 3 && m != 4 && m != 6 && m != 12)
            {
                clearArray(array, n);
                if(fillArray(array, m, n) == 0)
                {
                    found = 1;
                }
            }
            m++;
        }

        printf("%d\n");

        scanf("%d", &n);
    }

    return 0;
}

void clearArray(int* array, int n)
{
    for(int i = 1; i <= n; i++)
        array[i] = ON;
}

int fillArray(int* array, int m, int n)
{
    int i = 1, j, offCounter = 0, incrementCounter;

    while(offCounter != n)
    {
        if(*(array+i)==ON) 
        {
            *(array+i) = OFF;
            offCounter++;       
        }
        else 
        {
            j = 0;
            while((*array+i+j)==OFF)
            {
                j++;
            }
            *(array+i+j) = OFF;
            offCounter++;           
        }
        if(*(array+13) == OFF && offCounter != n) return 1;
        if(offCounter ==n) break;

        incrementCounter = 0;       
        while(incrementCounter != m)
        {
            i++;
            if(i > n) i = 1;
            if(*(array+i) == ON) incrementCounter++; 
        }       
    }

    return 0;
}
도움이 되었습니까?

해결책

당신은 "놀랍게도 프로그램이 컴파일됩니다"라고 말합니다. 사실, 전혀 놀라운 것은 아닙니다. C & C ++는 기능에 가변 인수 목록을 갖도록 허용합니다. printf의 정의는 다음과 같습니다.

int printf(char*, ...);

"..."는 함수에 대한 선택적 인수가 0 이상임을 나타냅니다. 실제로, C가 선택적 인수를 가진 주된 이유 중 하나는 printf & scanf 함수 패밀리를 지원하는 것입니다.

C는 printf 함수에 대한 특별한 지식이 없습니다. 예에서 :

printf("%d");

컴파일러는 형식 문자열을 분석하지 않고 정수 인수가 누락되었다고 판단합니다. 이것은 완벽하게 합법적 인 C 코드입니다. 당신이 논쟁을 놓치고 있다는 사실은 런타임에만 나타나는 의미 론적 문제입니다. printf 함수는 당신이 논증을 제공했다고 가정하고 스택에서 그것을 찾고 있습니다. 거기에있는 모든 일을 선택합니다. 특별한 경우에는 올바른 것을 인쇄하고 있지만 이것은 예외입니다. 일반적으로 쓰레기 데이터를 얻을 수 있습니다. 이 동작은 컴파일러마다 다르며 사용하는 컴파일 옵션에 따라 변경됩니다. 컴파일러 최적화를 켜면 다른 결과를 얻을 수 있습니다.

내 답변에 대한 주석 중 하나에서 지적한 바와 같이, 일부 컴파일러에는 실제로 잘못된 printf/scanf 호출을 감지 할 수있는 "Lint"기능이 있습니다. 여기에는 형식 문자열을 구문 분석하고 예상되는 추가 인수 수를 결정하는 컴파일러가 포함됩니다. 이것은 매우 특별한 컴파일러 동작이며 일반적인 경우 오류를 감지하지 않습니다. 즉, printf와 동일한 시그니처를 가진 자신의 "printf_better"기능을 작성하면 컴파일러가 인수가 누락 된 경우 감지하지 않습니다.

다른 팁

무슨 일이 일어나는지 이렇게 보입니다.

printf("%d", m);

대부분의 시스템에서 문자열의 주소가 스택에 밀려 나게됩니다. 'm' 정수로서 (int/short/char라고 가정). 경고가 없기 때문입니다 printf 기본적으로 다음과 같이 선언됩니다 'int printf(const char *, ...);' - ... '무엇이든 간다'는 의미입니다.

따라서 '무엇이든'변수를 넣을 때 이상한 일이 발생하기 때문입니다. int보다 작은 모든 적분 유형은 int와 같은 것입니다. 전혀 아무것도 보내지 않아도 괜찮습니다.

printf 구현 (또는 적어도 '간단한'구현)에서 사용법을 찾을 수 있습니다. va_list 그리고 va_arg (이름은 언젠가는 적합성에 따라 약간 다릅니다). 이것들은 구현이 인수 목록의 '...'를 걸어 다니는 데 사용하는 것입니다. 문제는 유형 확인이 없다는 것입니다. 유형 확인이 없으므로 printf 형식 문자열을 볼 때 임의 데이터를 실행 스택에서 가져옵니다. ("%d") 그리고 거기가 있어야한다고 생각합니다 'int' 다음.

어둠 속의 임의의 샷 'm-1' 두 번째 파마로? 그것은 많은 가능성 중 하나이지만 이것이 사실이라면 흥미로울 것입니다. :)

행운을 빕니다.

그건 그렇고 - 대부분의 최신 컴파일러 (GCC I Believe?)는이 문제를 감지 할 수있는 경고가 있습니다. Lint도 내가 믿는다. 불행히도 VC를 사용하면 무료로 얻는 대신 /분석 플래그를 사용해야한다고 생각합니다.

스택에서 int를 얻었습니다.

http://en.wikipedia.org/wiki/x86_calling_conventions

당신은 스택을 들여다보고 있습니다. Optimizer 값을 변경하면 변경 될 수 있습니다. 선언 순서 변경 변수 (특히) m. 만들다 m 레지스터 변수. 만들다 m 글로벌 변수.

무슨 일이 일어나는지에 대한 몇 가지 변형이 보입니다.

이것은 단순한 I/O를 할 때 얻는 유명한 버퍼 오버런 핵과 유사합니다.

나는 이것이 메모리 위반을 초래할 것이라고 의심하지만, 당신이 얻는 정수는 정의되지 않은 쓰레기입니다.

당신은 찾았습니다 하나 행동. 그랬을 수도 있습니다 어느 유효하지 않은 메모리 액세스를 포함한 기타 동작.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top