Rust print!()

Freeman·2024년 11월 7일

Rust

목록 보기
1/1
post-thumbnail

이번 글에서는 Rust표준 출력 매크로 중 하나인 print!()println!()에 대해 다뤄보겠습니다.

프로그래밍 언어를 배울 때 처음으로 접하게 되는 기능 중 하나가 바로 출력입니다. C++JAVA에서는 printf()System.out.print() 등을 사용하지만, Rust에서는 print!()println!() 매크로를 사용하여 출력합니다. 특히 println!은 print line의 약자로, 자동으로 줄바꿈을 포함하는 기능을 가지고 있습니다. 그렇다면 왜 Rust에서는 단순히 print()가 아닌 print!()처럼 !가 붙은 매크로 출력 기능을 제공할까요?

함수와 매크로의 차이

Rust에서 print!println!!가 붙은 이유는 이들이 일반 함수가 아닌 매크로이기 때문입니다. Rust에서 함수매크로는 중요한 차이가 있습니다.

  • 함수는 프로그램이 실행되는 동안 호출됩니다. 함수는 런타임에 전달된 인자를 기반으로 실행되며, 고정된 수의 인자를 받아 처리합니다.
  • 매크로는 함수와 달리 컴파일 타임에 코드가 확장(생성)되어, 호출된 위치에 실제 코드로 변환됩니다.

print!()println!이 매크로인 이유

print!println!()이 매크로로 설계된 이유는 가변적인 수의 인자를 받아서 처리하기 위해서입니다. 예를 들어, 문자열에 여러 개의 값을 포맷팅해서 출력할 때 println!() 매크로는 여러 인자를 한꺼번에 받아 처리할 수 있습니다.

fn main() {
    // 여러 인자를 받아 포맷팅하여 출력
    println!("Hello, {}!", "Rust");  
    // 다양한 인자 수와 타입 처리
    println!("Number: {}, Text: {}", 42, "Hello");
}

위의 코드에서처럼 println!은 가변 인자를 받아 다양한 타입과 수의 값을 출력할 수 있습니다. 이러한 유연성은 매크로이기 때문에 가능한 것입니다.

그렇다면 printf()는 매크로가 아닌가요?

C++JAVAprintf() 역시 가변 인자 처리가 가능합니다. 그러면 printf()도 매크로여야 할까요?
정답은 '아니요'입니다. printf()함수로 구현되어 있으며, 런타임에 전달된 인자를 처리합니다.

  • 가변 인자 배열: C++JAVAprintf()는 가변 인자를 처리하기 위해 가변 인자 배열을 생성하여 런타임에 전달된 인자를 처리합니다.
  • 런타임 오버헤드: printf()는 호출될 때마다 가변 인자 배열을 생성하고 메모리를 할당해 런타임 오버헤드가 발생할 수 있습니다.
  • 타입 안정성 부족: printf()는 컴파일 타임에 타입 검사를 수행하지 않기 때문에, 포맷 문자열과 인자 타입이 맞지 않으면 런타임에 오류가 발생할 수 있습니다.

Rust에서 매크로를 사용하는 이유

Rustprint!println!을 매크로로 구현하여 타입 안정성성능 최적화라는 두 가지 이점을 제공합니다.

  • 타입 안정성: println! 매크로는 컴파일 타임에 인자의 타입을 검사합니다. 따라서, 포맷 문자열과 인자의 타입이 맞지 않으면 컴파일 오류가 발생하여 안전하게 코드를 작성할 수 있습니다. 이는 printf()와 달리 런타임 예외가 발생하지 않도록 도와줍니다.
  • 성능 최적화: 매크로는 컴파일 타임에 코드가 확장(생성)되므로, 런타임 호출 오버헤드가 없습니다. print!println!은 컴파일 시점에 인자와 포맷 문자열이 최적화된 코드로 변환되기 때문에, 런타임 성능이 향상됩니다.

이러한 이유로, Rustprint!println!매크로로 구현하여 타입 안정성을 보장하면서도 효율적인 성능을 제공합니다.

0개의 댓글