HOWTO · Arduino

Arduino strcpy 함수

Arduino의 strcpy() 함수를 사용하여 한 변수에서 다른 변수로 하나의 문자열을 복사할 수 있습니다.

이 페이지의 내용

strcpy(destination, source)는 종료 문자 \0를 포함해 널 종료 C 문자열을 복사합니다. 대상 배열에는 원본의 모든 문자와 종료 문자가 들어갈 공간이 있어야 합니다. 예를 들어 "Hello World"에는 12바이트가 필요합니다. 이 함수는 문자 배열에 사용하며 Arduino String 객체에는 사용할 수 없습니다. 원본과 대상이 겹치는 경우에도 사용하지 마세요.

strcpy()와 널 종료 문자열 이해하기

C 문자열은 문자 뒤에 널 바이트(\0)가 오는 시퀀스입니다. strcpy()에는 쓰기 가능한 대상 포인터와 해당 문자열을 가리키는 원본 포인터를 전달합니다. 이 함수는 원본의 종료 문자까지 복사하고 대상 포인터를 반환합니다. 원본은 const char *로 선언할 수 있지만 대상은 쓰기 가능해야 합니다.

이 함수에는 대상의 용량을 전달하지 않으므로 배열이 충분히 큰지 확인할 수 없습니다. 모든 문자와 종료 문자를 담을 공간이 부족하면 프로그램의 동작은 정의되지 않습니다. 실행 결과가 정상처럼 보여도 크기가 부족한 복사가 안전해지는 것은 아닙니다. char name[] 같은 C 문자열과 다른 인터페이스를 사용하는 Arduino String 객체도 구분해야 합니다.

strcpy()로 문자열 안전하게 복사하기

이 완전한 스케치는 "Hello World"의 11개 문자와 종료 문자 \0를 12바이트 배열에 복사한 다음, 복사된 문자열을 Serial로 출력합니다. 아래의 호스트 측 Serial 대체 구현을 사용하면 같은 setup() 로직을 독립 실행형 예제로 실행할 수 있습니다. Arduino 보드에서는 코어가 Serial을 제공하고 setup()을 호출합니다. 코드와 출력 블록은 변경하지 않으므로 예제에 표시되는 Hello World는 영어로 남아 있습니다.

#include <cstring>
#ifndef ARDUINO
#include <iostream>
struct SerialPort {
    void begin(unsigned long) {}
    void println(const char* value) { std::cout << value << '\n'; }
} Serial;
#endif

const char source[] = "Hello World";
char destination[sizeof(source)]; // 12 bytes: 11 characters plus \0

void setup() {
    Serial.begin(9600);
    std::strcpy(destination, source);
    Serial.println(destination);
}

void loop() {
    // The copy is performed once in setup().
}

#ifndef ARDUINO
int main() {
    setup();
    return 0;
}
#endif
Hello World

이 고정된 원본에서는 sizeof(source)에 종료 문자가 포함되므로 대상 용량은 12바이트입니다. 텍스트를 가리키는 포인터에 sizeof(pointer)를 적용하면 문자열 길이가 아니라 포인터 크기만 얻습니다. 이 경우에는 문자열 길이에 1을 더해 필요한 용량을 계산하세요. 원본과 대상은 서로 겹치지 않는 별도 저장 공간이어야 합니다. 다음 호스트 C 예제는 설정된 실행 환경에서 같은 고정 문자열 복사를 보여 줍니다.

#include <stdio.h>
#include <string.h>

int main(void) {
    const char source[] = "Hello World";
    char destination[sizeof(source)];

    strcpy(destination, source);
    puts(destination);
    return 0;
}
Hello World

strncpy()와 strlcpy() 비교하기

strncpy(destination, source, count)는 최대 count바이트를 복사합니다. 원본이 count보다 먼저 끝나면 남은 대상 바이트를 널 바이트로 채웁니다. 원본이 count바이트 이상이면 종료 문자를 추가하지 않습니다. 따라서 strncpy()가 대상 용량까지 채운 경우에는 종료가 확인될 때까지 그 배열을 문자열 함수에 전달하면 안 됩니다. 용량이 0보다 큰 대상 배열에서는 최대 capacity - 1바이트를 복사한 뒤 destination[capacity - 1] = '\0'을 설정하는 방법을 흔히 사용합니다. 이렇게 하면 종료된 문자열을 얻지만, 문자열이 잘렸을 수 있으며 원본의 유효성을 검사하거나 다른 메모리 오류를 막아 주지는 않습니다.

strlcpy(destination, source, size)의 size에는 \0을 넣을 공간까지 포함한 전체 대상 용량을 전달합니다. size가 0보다 크면 대상 문자열을 종료하고, 필요한 경우 내용을 자릅니다. 반환값은 원본 전체의 길이이므로 size와 비교해 잘림 여부를 확인할 수 있습니다. 모든 환경에서 사용할 수 있는 함수는 아니므로 사용 전에 선택한 Arduino 코어와 툴체인이 strlcpy()를 제공하는지 확인하세요. 제공하지 않는다면 지원되는 함수나 용량을 신중하게 계산한 복사 방법을 사용하세요.

Serial 입력을 문자 배열에 복사하기

이 스케치는 32바이트 입력 배열에 최대 31바이트를 읽고, 반환된 바이트 수 위치에 종료 문자를 쓴 다음, 만들어진 C 문자열을 별도의 32바이트 대상 배열에 복사해 출력합니다. 보드에서는 Arduino의 Serial API를 사용합니다. 아래 호스트 실행 예제에서는 작은 대체 구현이 샘플 줄 Hello World를 제공하므로 하드웨어 없이도 복사 로직을 실행할 수 있습니다. 코드와 출력 블록은 변경하지 않으며, 예제에 표시되는 Hello World는 영어로 남아 있습니다.

#include <cstddef>
#include <cstring>
#ifndef ARDUINO
#include <iostream>
struct SerialPort {
    void begin(unsigned long) {}
    void setTimeout(unsigned long) {}
    void println(const char* value) { std::cout << value << '\n'; }
    std::size_t readBytesUntil(char delimiter, char* buffer, std::size_t capacity) {
        const char sample[] = "Hello World";
        std::size_t count = 0;
        while (count < capacity && sample[count] != '\0' && sample[count] != delimiter) {
            buffer[count] = sample[count];
            ++count;
        }
        return count;
    }
} Serial;
#endif

const std::size_t INPUT_CAPACITY = 32;
char inputBuffer[INPUT_CAPACITY];
char destination[INPUT_CAPACITY];

void setup() {
    Serial.begin(9600);
    Serial.setTimeout(1000);
    Serial.println("Enter a line:");

    std::size_t bytesRead = Serial.readBytesUntil('\n', inputBuffer, INPUT_CAPACITY - 1);
    inputBuffer[bytesRead] = '\0';
    std::strcpy(destination, inputBuffer);
    Serial.println(destination);
}

void loop() {
    // This one-shot input example runs once in setup().
}

#ifndef ARDUINO
int main() {
    setup();
    return 0;
}
#endif
Enter a line:
Hello World

readBytesUntil()은 \n을 읽거나, 1000ms 제한 시간이 끝나거나, 31바이트를 읽으면 멈춥니다. 반환되는 size_t 값은 최대 31이므로 inputBuffer[bytesRead] = '\0'을 쓰더라도 32바이트 배열의 범위를 벗어나지 않습니다. 대상 배열도 같은 용량이므로 복사된 바이트와 종료 문자를 담을 수 있습니다. 줄 바꿈 문자를 만나기 전에 줄이 31바이트에 도달하면 나머지 내용이 다음 읽기까지 남을 수 있습니다. 시간 제한이 끝나면 일부 내용만 반환될 수도 있습니다. 줄 바꿈 구분자는 발견 시 소비되지만, 이 코드는 앞에 있는 \r을 제거하지 않으므로 출력 문자열 끝에 남을 수 있습니다. 애플리케이션에서 필요하다면 명시적으로 제거하세요.

복사 함수를 선택하고 버퍼 용량 확인하기

복사하기 전에 값이 Arduino String인지 널 종료 문자 배열인지 확인하세요. C 문자열은 \0 한 바이트를 포함해 용량을 바이트 단위로 계산해야 합니다. UTF-8 텍스트에서는 문자 수와 바이트 수가 다를 수 있습니다. 원본 전체가 들어가는 용량을 알고 있을 때만 strcpy()를 사용하세요. strncpy()를 사용할 때는 종료와 패딩을 어떻게 처리할지 명확히 계획해야 합니다. 대상이 strlcpy()를 제공한다면 이를 사용하고 반환값으로 잘림 여부를 확인하세요. Serial 데이터는 입력 배열 용량을 넘지 않게 읽고, 반환된 바이트 수 위치에 종료 문자를 쓴 뒤, 결과 문자열을 복사할 모든 대상 배열의 용량을 확인하세요.