IT Share you

C에서 매번 데이터 유형을 지정해야하는 이유는 무엇입니까?

shareyou 2020. 11. 12. 20:36
반응형

C에서 매번 데이터 유형을 지정해야하는 이유는 무엇입니까?


아래 코드 스 니펫에서 볼 수 있듯이 char변수 하나와 int변수 하나를 선언했습니다 . 코드가 컴파일되면 변수 stri.

%s또는 %dto 를 지정하여 변수를 검색하는 동안 문자열 또는 정수 변수임을 다시 알려야하는 이유는 무엇 scanf입니까? 컴파일러가 내 변수를 선언했을 때이를 식별 할만큼 충분히 성숙하지 않았나요?

#include <stdio.h>

int main ()
{
  char str [80];
  int i;

  printf ("Enter your family name: ");
  scanf ("%s",str);  
  printf ("Enter your age: ");
  scanf ("%d",&i);

  return 0;
}

이 같은 가변 인수 기능에 대한 호환성있는 방법은 없습니다 때문에 scanfprintf많은 인수가 전달되지도 방법, 변수 인수의 유형을 알 수 있습니다.

C FAQ : 함수가 실제로 호출 된 인수 수를 어떻게 알 수 있습니까?를 참조하십시오.


이것이 변수 인수의 수와 유형을 결정하기 위해 적어도 하나의 고정 인수가 있어야하는 이유입니다. 그리고이 인수 (표준에서는이를 호출합니다 parmN. C11 ( ISO / IEC 9899 : 201x ) §7.16 가변 인수 참조 )가이 특별한 역할을 수행하며 매크로에 전달됩니다 va_start. 다시 말해, 표준 C에서는 다음과 같은 프로토 타입이있는 함수를 가질 수 없습니다.

void foo(...);

컴파일러가 여기에 관여하지 않기 때문에 컴파일러가 필요한 정보를 제공하지 못하는 이유는 간단합니다. 함수의 프로토 타입은 유형을 지정하지 않습니다. 이러한 함수에는 변수 유형이 있기 때문입니다. 따라서 실제 데이터 유형은 컴파일 타임이 아니라 런타임에 결정됩니다. 그런 다음 함수는 스택에서 인수를 하나씩받습니다. 이러한 값에는 연결된 유형 정보가 없으므로 함수가 데이터를 해석하는 방법을 아는 유일한 방법은 형식 문자열 인 호출자가 제공 한 정보를 사용하는 것입니다.

함수 자체는 전달되는 데이터 유형을 알지 못하며 전달 된 인수의 수를 알지 못하므로 printf이를 스스로 결정할 수있는 방법이 없습니다 .

C ++에서는 연산자 오버로딩을 사용할 수 있지만 이는 완전히 다른 메커니즘입니다. 여기에서 컴파일러는 데이터 유형 및 사용 가능한 오버로드 된 함수를 기반으로 적절한 함수를 선택하기 때문입니다.

이를 설명하기 위해 printf컴파일하면 다음과 같습니다.

 push value1
 ...
 push valueN
 push format_string
 call _printf

의 프로토 타입 printf은 다음과 같습니다.

int printf ( const char * format, ... );

따라서 형식 문자열에서 제공되는 내용을 제외하고는 전달되는 유형 정보가 없습니다.


printf내장 함수 가 아닙니다 . 그것은 그 자체로 C 언어의 일부가 아닙니다. 컴파일러는 printf모든 매개 변수를 전달 하여를 호출 할 코드를 생성합니다 . 이제 C는 런타임에 형식 정보를 파악하는 메커니즘으로 리플렉션제공하지 않기 때문에 프로그래머는 필요한 정보를 명시 적으로 제공해야합니다.


컴파일러는 영리 할 수 ​​있지만 함수 printf이거나 scanf어리 석습니다. 모든 호출에 대해 전달하는 매개 변수의 유형이 무엇인지 모릅니다. 당신이 통과해야하는 이유입니다 %s또는 %d때마다.


첫 번째 매개 변수는 형식 문자열 입니다. 10 진수를 인쇄하는 경우 다음과 같이 표시 될 수 있습니다.

  • "%d" (10 진수)
  • "%5d" (공백으로 너비 5로 채워진 십진수)
  • "%05d" (0으로 너비 5로 채워진 10 진수)
  • "%+d" (항상 부호가있는 10 진수)
  • "Value: %d\n" (숫자 전후의 일부 내용)

등, 예를 들어 Wikipedia의 Format placeholders를 참조하여 어떤 형식 문자열이 포함될 수 있는지 알 수 있습니다.

또한 여기에 둘 이상의 매개 변수가있을 수 있습니다.

"%s - %d" (문자열, 내용, 숫자)


컴파일러가 내 변수를 선언했을 때이를 식별 할만큼 충분히 성숙하지 않았나요?

아니.

수십 년 전에 지정된 언어를 사용하고 있습니다. 현대적인 언어가 아니기 때문에 C에서 현대적인 디자인 미학을 기대하지 마십시오. 현대 언어는 유용성 또는 명확성을 향상시키기 위해 컴파일, 해석 또는 실행에서 약간의 효율성을 교환하는 경향이 있습니다. C는 컴퓨터 처리 시간이 비싸고 공급이 매우 제한되었던 시대에서 비롯되었으며, 그 디자인은이를 반영합니다.

또한 C와 C ++가 빠르고 효율적이거나 금속에 가까워지는 것에 정말로 관심을 가질 때 선택하는 언어로 남아있는 이유이기도합니다.


scanf프로토 타입 int scanf ( const char * format, ... );은 매개 변수 형식에 따라 주어진 데이터를 추가 인수가 가리키는 위치에 저장한다고 말합니다.

It is not related with compiler, it is all about syntax defined for scanf.Parameter format is required to let scanf know about the size to reserve for data to be entered.


GCC (and possibly other C compilers) keep track of argument types, at least in some situations. But the language is not designed that way.

The printf function is an ordinary function which accepts variable arguments. Variable arguments require some kind of run-time-type identification scheme, but in the C language, values do not carry any run time type information. (Of course, C programmers can create run-time-typing schemes using structures or bit manipulation tricks, but these are not integrated into the language.)

When we develop a function like this:

void foo(int a, int b, ...);

we can pass "any" number of additional arguments after the second one, and it is up to us to determine how many there are and what are their types using some sort of protocol which is outside of the function passing mechanism.

For instance if we call this function like this:

foo(1, 2, 3.0);
foo(1, 2, "abc");

there is no way that the callee can distinguish the cases. There are just some bits in a parameter passing area, and we have no idea whether they represent a pointer to character data or a floating point number.

The possibilities for communicating this type of information are numerous. For example in POSIX, the exec family of functions use variable arguments which have all the same type, char *, and a null pointer is used to indicate the end of the list:

#include <stdarg.h>

void my_exec(char *progname, ...)
{
  va_list variable_args;
  va_start (variable_args, progname);

  for (;;) {
     char *arg = va_arg(variable_args, char *);
     if (arg == 0)
       break;
     /* process arg */
  }

  va_end(variable_args);
  /*...*/
}

If the caller forgets to pass a null pointer terminator, the behavior will be undefined because the function will keep invoking va_arg after it has consumed all of the arguments. Our my_exec function has to be called like this:

my_exec("foo", "bar", "xyzzy", (char *) 0);

The cast on the 0 is required because there is no context for it to be interpreted as a null pointer constant: the compiler has no idea that the intended type for that argument is a pointer type. Furthermore (void *) 0 isn't correct because it will simply be passed as the void * type and not char *, though the two are almost certainly compatible at the binary level so it will work in practice. A common mistake with that type of exec function is this:

my_exec("foo", "bar", "xyzzy", NULL);

where the compiler's NULL happens to be defined as 0 without any (void *) cast.

Another possible scheme is to require the caller to pass down a number which indicates how many arguments there are. Of course, that number could be incorrect.

In the case of printf, the format string describes the argument list. The function parses it and extracts the arguments accordingly.

As mentioned at the outset, some compilers, notably the GNU C Compiler, can parse format strings at compile time and perform static type checking against the number and types of arguments.

However, note that a format string can be other than a literal, and may be computed at run time, which is impervious to such type checking schemes. Fictitious example:

char *fmt_string = message_lookup(current_language, message_code);

/* no type checking from gcc in this case: fmt_string could have
   four conversion specifiers, or ones not matching the types of
   arg1, arg2, arg3, without generating any diagnostic. */
snprintf(buffer, sizeof buffer, fmt_string, arg1, arg2, arg3);

It is because this is the only way to tell the functions (like printf scanf) that which type of value you are passing. for example-

int main()
{
    int i=22;
    printf("%c",i);
    return 0;
}

this code will print character not integer 22. because you have told the printf function to treat the variable as char.


printf and scanf are I/O functions that are designed and defined in a way to receive a control string and a list of arguments.

The functions does not know the type of parameter passed to it , and Compiler also cant pass this information to it.


Because in the printf you're not specifying data type, you're specifying data format. This is an important distinction in any language, and it's doubly important in C.

When you scan in a string with with %s, you're not saying "parse a string input for my string variable." You can't say that in C because C doesn't have a string type. The closest thing C has to a string variable is a fixed-size character array that happens to contain a characters representing a string, with the end of string indicated by a null character. So what you're really saying is "here's an array to hold the string, I promise it's big enough for the string input I want you to parse."

Primitive? Of course. C was invented over 40 years ago, when a typical machine had at most 64K of RAM. In such an environment, conserving RAM had a higher priority than sophisticated string manipulation.

Still, the %s scanner persists in more advanced programming environments, where there are string data types. Because it's about scanning, not typing.

참고URL : https://stackoverflow.com/questions/18203636/why-do-i-have-to-specify-data-type-each-time-in-c

반응형