기술적으로, 가변 함수는 어떻게 작동합니까?printf는 어떻게 작동합니까?
도 쓸 수 거 알아va_arg예를 들어 조립 지침 수준에서 후드 아래에서 가변 함수는 어떻게 작동합니까?
를 들면, 「」가 「:」가 되는 이 가능합니까?printf수수 개개 ?? ??? ????
* 예외 없는 규칙은 없습니다.언어 C/C++는 없지만, 이 질문에는 둘 다 답변할 수 있습니다.
* 주의:원래 "프린트 f 함수는 변수 파라미터를 출력하는 동안 수치로 취득할 수 있는 방법"에 대한 답변이지만 질문자에게는 적용되지 않은 것 같습니다.
C 및 C++ 규격에는 동작 방법에 대한 요건이 없습니다.한 컴파일러는 「」를 .std::stack<boost::any>혹은 (@Xeo의 코멘트에 따라) 후드 밑에 있는 마법의 조랑말 가루도.
단, CPU 레지스터의 인라인이나 인수 전달과 같은 변환이 논의된 코드의 어떤 것도 남기지 않는 경우에도 보통 다음과 같이 구현됩니다.
또, 이 답변은, 아래의 그림으로 스택의 하향을 구체적으로 나타내고 있는 것에 주의해 주세요.또, 이 답변은 스킴을 설명하기 위한 단순한 것입니다(https://en.wikipedia.org/wiki/Stack_frame) 참조).
고정되지 않은 수의 인수를 사용하여 함수를 호출하려면 어떻게 해야 합니까?
이는 기본 시스템 아키텍처에 모든 스레드에 대해 이른바 "스택"이 있기 때문에 가능합니다.스택은 인수를 함수에 전달하기 위해 사용됩니다.예를 들어 다음과 같은 경우:
foobar("%d%d%d", 3,2,1);
그런 다음 다음과 같은 어셈블러 코드로 컴파일됩니다(예: 도식적으로 실제 코드는 다르게 보일 수 있습니다). 인수는 오른쪽에서 왼쪽으로 전달됩니다.
push 1
push 2
push 3
push "%d%d%d"
call foobar
이러한 푸시 조작은 스택을 가득 채웁니다.
[] // empty stack
-------------------------------
push 1: [1]
-------------------------------
push 2: [1]
[2]
-------------------------------
push 3: [1]
[2]
[3] // there is now 1, 2, 3 in the stack
-------------------------------
push "%d%d%d":[1]
[2]
[3]
["%d%d%d"]
-------------------------------
call foobar ... // foobar uses the same stack!
맨 아래 스택 요소는 "Top of Stack"으로 불리며 종종 "TOS"로 약칭됩니다.
foobar함수는 TOS에서 시작하여 스택에 액세스합니다.즉, 마지막으로 푸시된 포맷 문자열입니다.stack포인터입니다.stack[0], TOS 값입니다.stack[1]TOS 위에 있는 것 등입니다.
format_string <- stack[0]
합니다.포맷 문자열을 해석합니다. 「」를 합니다.%d됩니다. 즉, 스택에서 값이 하나 더 로드됩니다.
format_string <- stack[0]
offset <- 1
while (parsing):
token = tokenize_one_more(format_string)
if (needs_integer (token)):
value <- stack[offset]
offset = offset + 1
...
이는 물론 함수가 스택에서 로드 및 삭제해야 하는 양을 확인하기 위해 전달된 인수에 의존해야 하는 매우 불완전한 의사 코드입니다.
보안.
사용자가 제공한 인수에 의존하는 것도 존재하는 가장 큰 보안 문제 중 하나입니다(https://cwe.mitre.org/top25/) 참조).사용자는 문서를 읽지 않았거나 형식 문자열 또는 인수 목록을 조정하는 것을 잊었거나 완전히 악의적이어서 바리에타드 함수를 잘못 사용할 수 있습니다.「String Attack 포맷」도 참조해 주세요.
C의 실장
및 C++, Variadic 가 사용됩니다.va_list인터페이스입니다.스택으로의 푸시는 이러한 언어(K+R C에서는 인수를 기술하지 않고 함수를 포워드 선언할 수도 있지만 여전히 임의의 숫자와 친절한 인수를 사용하여 호출할 수도 있음)에 고유한 것이지만 이러한 알 수 없는 인수 목록에서 읽기는 를 통해 이루어집니다.va_... -의 두 번째va_list를 추상화합니다.-type : " "적 。
가변 함수는 표준에 의해 정의되며 명시적인 제한은 거의 없습니다.다음은 cplusplus.com에서 가져온 예입니다.
/* va_start example */
#include <stdio.h> /* printf */
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
void PrintFloats (int n, ...)
{
int i;
double val;
printf ("Printing floats:");
va_list vl;
va_start(vl,n);
for (i=0;i<n;i++)
{
val=va_arg(vl,double);
printf (" [%.2f]",val);
}
va_end(vl);
printf ("\n");
}
int main ()
{
PrintFloats (3,3.14159,2.71828,1.41421);
return 0;
}
가정은 대략 다음과 같다.
- 첫 번째(적어도 1개 이상) 고정 명명된 인수가 있어야 합니다.
...컴파일러에게 올바른 일을 하라고 지시하는 것 이외에는 아무것도 하지 않습니다. - fixed 인수(들)는 지정되지 않은 메커니즘에 의해 존재하는 가변 인수의 수에 대한 정보를 제공합니다.
- , 「」는 사용할 수 .
va_start: 할 수 합니다.은 「」입니다.va_list. - 서
va_list: " " " " "에 가능합니다.va_arg각 변수 인수에 대해 반복하고 해당 값을 호환 가능한 유형으로 강제합니다. - something something something something something something something something something something something something something something something
va_startva_end다시 바로잡는 거야
, 「 」는 「 」입니다.va_list상에 또, 「」는 「」입니다.va_arg는 포인터를 증분하여 캐스팅하고 값으로 되돌립니다. ★★★★★★★★★★★★★★★.va_start는, 및 내부 지식)과 「내부 지식」으로 합니다.va_end아무것도 하지 않습니다.이상한 어셈블리 언어는 없습니다.물건이 쌓여 있는 장소에 대한 내부 지식일 뿐입니다.표준 헤더의 매크로를 읽고, 그 내용을 확인합니다.
일부 컴파일러(MSVC)에서는 특정 콜시퀀스가 필요합니다.이것에 의해, 발신자는 착신측이 아닌 스택을 해방합니다.
음음음 functions 등의 printf이치노fixed 인수는 형식 문자열로 인수 수를 계산할 수 있습니다.
음음음 functions 등의 vsprintf을 va_list를 normal object로 합니다.
자세한 내용은 질문에 추가해 주세요.
언급URL : https://stackoverflow.com/questions/23104628/technically-how-do-variadic-functions-work-how-does-printf-work
'source' 카테고리의 다른 글
| SQL 주입 MariaDB python CTF (0) | 2023.01.05 |
|---|---|
| Java 휘발성 참조와아토믹 레퍼런스 (0) | 2023.01.05 |
| 웹 서버에서 중첩된 산술 MySQL 쿼리에 대한 문제 (0) | 2023.01.05 |
| Python 객체가 문자열인지 확인하는 방법 (0) | 2023.01.05 |
| PHP에서 문자열을 부울 값으로 구문 분석 (0) | 2023.01.05 |