# UploadBytesAsync 동작 플로우

```mermaid
flowchart TD
    A[메서드 호출: UploadBytesAsync] --> B[입력값 검증: data가 null인지 확인]
    B -->|null이면 예외| X[ArgumentNullException 발생]
    B -->|정상| C[MemoryStream 생성 (data)]
    C --> D[UploadStreamInternalAsync 호출]
    D --> E[내부에서 FTP 업로드 진행]
    E --> F[업로드 완료]
```

## UploadBytesAsync 네트워크 시퀀스 다이어그램

```mermaid
sequenceDiagram
    participant App as 사용자 코드
    participant FtpClient as FtpClient
    participant NIC as 네트워크 인터페이스
    participant FTPServer as FTP 서버

    App->>FtpClient: UploadBytesAsync(remotePath, data)
    FtpClient->>NIC: FTP 연결 요청 (TCP SYN)
    NIC->>FTPServer: TCP SYN
    FTPServer->>NIC: TCP SYN+ACK
    NIC->>FtpClient: TCP SYN+ACK
    FtpClient->>NIC: TCP ACK
    NIC->>FTPServer: TCP ACK

    FtpClient->>FTPServer: USER 명령 (아이디 전송)
    FTPServer->>FtpClient: 331 User name okay, need password
    FtpClient->>FTPServer: PASS 명령 (비밀번호 전송)
    FTPServer->>FtpClient: 230 User logged in

    FtpClient->>FTPServer: TYPE I (Binary 모드)
    FTPServer->>FtpClient: 200 Command okay
    FtpClient->>FTPServer: PASV (Passive 모드 요청)
    FTPServer->>FtpClient: 227 Entering Passive Mode (IP,Port)

    FtpClient->>FTPServer: STOR remotePath (업로드 시작)
    FTPServer->>FtpClient: 150 File status okay; about to open data connection

    FtpClient->>NIC: 데이터 전송 (MemoryStream의 byte[])
    NIC->>FTPServer: 데이터 패킷 전송
    FTPServer->>FtpClient: 226 Closing data connection (업로드 완료)

    FtpClient->>FTPServer: QUIT
    FTPServer->>FtpClient: 221 Service closing control connection
```

FtpClient.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace FtpClient
{
    // FTP 클라이언트 기능을 제공하는 클래스
    public class FtpClient
    {
        // FTP 접속 및 설정 정보를 담는 구성 객체
        private readonly FtpClientConfig _config;

        // 생성자: FTP 설정 객체를 받아서 초기화
        public FtpClient(FtpClientConfig config)
        {
            // config가 null이면 예외 발생
            _config = config ?? throw new ArgumentNullException(nameof(config));
        }

        /// <summary>
        /// 로컬 파일에서 FTP로 업로드 (디스크에 있는 파일 사용)
        /// </summary>
        public Task UploadFileAsync(string remotePath, string localFilePath, CancellationToken cancellationToken = default(CancellationToken))
        {
            // 업로드할 로컬 파일 경로가 null 또는 빈 문자열이면 예외 발생
            if (string.IsNullOrEmpty(localFilePath))
                throw new ArgumentNullException(nameof(localFilePath));

            // 파일이 실제로 존재하지 않으면 예외 발생
            if (!File.Exists(localFilePath))
                throw new FileNotFoundException("Local file not found.", localFilePath);

            // 내부 공통 업로드 메서드 호출 (파일 스트림 생성)
            return UploadStreamInternalAsync(remotePath, () => File.OpenRead(localFilePath), cancellationToken);
        }

        /// <summary>
        /// 메모리에 있는 byte 배열을 바로 FTP로 업로드 (디스크 사용 X)
        /// </summary>
        public Task UploadBytesAsync(string remotePath, byte[] data, CancellationToken cancellationToken = default(CancellationToken))
        {
            // 업로드할 데이터가 null이면 예외 발생
            if (data == null) throw new ArgumentNullException(nameof(data));

            // MemoryStream을 바로 사용하여 업로드
            return UploadStreamInternalAsync(
                remotePath,
                () => new MemoryStream(data, writable: false),
                cancellationToken);
        }

        /// <summary>
        /// 이미 가지고 있는 Stream을 FTP로 업로드 (디스크 사용 X).
        /// Stream의 Position은 적절히 설정되어 있다고 가정.
        /// </summary>
        public Task UploadStreamAsync(string remotePath, Stream dataStream, CancellationToken cancellationToken = default(CancellationToken))
        {
            // 업로드할 스트림이 null이면 예외 발생
            if (dataStream == null) throw new ArgumentNullException(nameof(dataStream));
            // 스트림이 읽을 수 없으면 예외 발생
            if (!dataStream.CanRead) throw new ArgumentException("Stream must be readable.", nameof(dataStream));

            // 외부에서 전달한 Stream은 dispose하지 않음
            return UploadStreamInternalAsync(remotePath, () => dataStream, cancellationToken, disposeStream: false);
        }

        /// <summary>
        /// 내부 공통 구현부 (Stream을 FTP로 업로드)
        /// </summary>
        private async Task UploadStreamInternalAsync(
            string remotePath,
            Func<Stream> streamFactory,
            CancellationToken cancellationToken,
            bool disposeStream = true)
        {
            // 업로드할 FTP 경로가 null 또는 빈 문자열이면 예외 발생
            if (string.IsNullOrEmpty(remotePath))
                throw new ArgumentNullException(nameof(remotePath));

            // FTP 업로드용 URI 생성
            Uri uri = _config.BuildUri(remotePath);

            // FTP 업로드 요청 객체 생성 및 각종 옵션 설정
            var request = (FtpWebRequest)WebRequest.Create(uri);
            request.Method = WebRequestMethods.Ftp.UploadFile; // 업로드 명령 지정
            request.Credentials = _config.ToCredential();      // 인증 정보 설정
            request.EnableSsl = _config.UseSsl;                // SSL 사용 여부 지정
            request.UsePassive = _config.UsePassive;           // Passive 모드 사용 여부 지정
            request.UseBinary = _config.UseBinary;             // 바이너리 모드 사용 여부 지정
            request.KeepAlive = false;                         // 업로드 후 연결 유지 안함

            Stream requestStream = null; // FTP 서버로 데이터 전송할 스트림
            Stream sourceStream = null;  // 실제 업로드할 데이터 스트림

            try
            {
                // 취소 요청이 들어오면 예외 발생
                cancellationToken.ThrowIfCancellationRequested();

                // FTP 서버로 데이터 전송 스트림 획득
                requestStream = await request.GetRequestStreamAsync().ConfigureAwait(false);

                // 실제 데이터를 제공할 스트림 생성 (파일/메모리)
                sourceStream = streamFactory();
                if (sourceStream == null)
                    throw new InvalidOperationException("Stream factory returned null.");

                // 데이터를 복사할 때 사용할 버퍼(80KB) 생성
                byte[] buffer = new byte[81920];
                int bytesRead;
                // sourceStream에서 데이터를 읽어서 FTP 서버로 전송
                while ((bytesRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0)
                {
                    await requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
                }

                // 서버의 응답을 받아 업로드 성공 여부 확인
                using (var response = (FtpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
                {
                    // 필요하다면 response.StatusDescription 로깅 가능
                    // Console.WriteLine($"Upload File Complete, status {response.StatusDescription}");
                }
            }
            finally
            {
                // disposeStream 옵션에 따라 sourceStream 자원 해제
                if (disposeStream && sourceStream != null)
                    sourceStream.Dispose();

                // FTP 서버로 데이터 전송 스트림 자원 해제
                if (requestStream != null)
                    requestStream.Dispose();
            }
        }

        /// <summary>
        /// 여러 chunk 파일을 순서대로 이어붙여 FTP 서버에 하나의 파일로 업로드한다.
        /// chunkPaths 순서대로 데이터를 Write 하며, 서버에는 단일 파일로 저장된다.
        /// </summary>
        public async Task UploadLargeFileAsync(
            string remotePath,
            IList<string> chunkPaths,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            // 업로드할 FTP 경로가 null 또는 빈 문자열이면 예외 발생
            if (string.IsNullOrEmpty(remotePath))
                throw new ArgumentNullException(nameof(remotePath));

            // chunkPaths가 null이거나 비어 있으면 예외 발생
            if (chunkPaths == null || chunkPaths.Count == 0)
                throw new ArgumentException("chunkPaths must contain at least one file path.");

            // FTP 업로드용 URI 생성
            Uri uri = _config.BuildUri(remotePath);

            // FTP 업로드 요청 객체 생성 및 각종 옵션 설정
            var request = (FtpWebRequest)WebRequest.Create(uri);
            request.Method = WebRequestMethods.Ftp.UploadFile; // 업로드 명령 지정
            request.Credentials = _config.ToCredential();      // 인증 정보 설정
            request.EnableSsl = _config.UseSsl;                // SSL 사용 여부 지정
            request.UsePassive = _config.UsePassive;           // Passive 모드 사용 여부 지정
            request.UseBinary = _config.UseBinary;             // 바이너리 모드 사용 여부 지정
            request.KeepAlive = false;                         // 업로드 후 연결 유지 안함

            Stream requestStream = null; // FTP 서버로 데이터 전송할 스트림

            try
            {
                // 취소 요청이 들어오면 예외 발생
                cancellationToken.ThrowIfCancellationRequested();

                // FTP 서버로 데이터 전송 스트림 획득
                requestStream = await request.GetRequestStreamAsync().ConfigureAwait(false);

                // chunk 쓰기 버퍼
                byte[] buffer = new byte[1024 * 1024]; // 1MB
                int bytesRead;

                // chunkPaths에 있는 각 파일을 순서대로 처리
                foreach (var path in chunkPaths)
                {
                    // 취소 요청이 들어오면 예외 발생
                    cancellationToken.ThrowIfCancellationRequested();

                    // 파일이 실제로 존재하는지 확인, 없으면 예외 발생
                    if (!File.Exists(path))
                        throw new FileNotFoundException("Chunk file not found: " + path);

                    // 파일을 읽기 전용으로 스트림을 열어서 사용
                    using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // 파일 스트림에서 데이터를 버퍼 단위로 읽어서 FTP 서버로 전송
                        while ((bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
                                        .ConfigureAwait(false)) > 0)
                        {
                            await requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken)
                                               .ConfigureAwait(false);
                        }
                    }
                }

                // 서버의 응답을 받아 업로드 성공 여부 확인
                using (var response = (FtpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
                {
                    // 필요시 response.StatusDescription 사용
                }
            }
            finally
            {
                // FTP 서버로 데이터 전송 스트림 자원 해제
                if (requestStream != null)
                    requestStream.Dispose();
            }
        }

        /// <summary>
        /// 첫 번째 chunk는 메모리(byte[])에서 읽고,
        /// 이후 chunk들은 파일에서 읽어 순서대로 이어붙여
        /// FTP 서버에 하나의 파일로 업로드한다.
        /// </summary>
        public async Task UploadLargeFileWithMemoryAsync(
            string remotePath,
            byte[] memoryChunk,
            IList<string> chunkPaths,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            // 업로드할 FTP 경로가 null 또는 빈 문자열이면 예외 발생 (필수 입력값 검증)
            if (string.IsNullOrEmpty(remotePath))
                throw new ArgumentNullException(nameof(remotePath));

            // 첫 번째 chunk로 사용할 메모리 데이터가 null이면 예외 발생 (필수 입력값 검증)
            if (memoryChunk == null)
                throw new ArgumentNullException(nameof(memoryChunk));

            // 이어붙일 파일 chunk 목록이 null이면 예외 발생 (필수 입력값 검증)
            if (chunkPaths == null)
                throw new ArgumentNullException(nameof(chunkPaths));

            // FTP 서버에 업로드할 파일의 URI를 생성 (경로 조합)
            Uri uri = _config.BuildUri(remotePath);

            // FTP 업로드 요청 객체 생성 및 각종 옵션 설정
            var request = (FtpWebRequest)WebRequest.Create(uri);
            request.Method = WebRequestMethods.Ftp.UploadFile; // FTP 업로드 명령 지정
            request.Credentials = _config.ToCredential();      // FTP 인증 정보 설정
            request.EnableSsl = _config.UseSsl;                // SSL 사용 여부 지정
            request.UsePassive = _config.UsePassive;           // Passive 모드 사용 여부 지정
            request.UseBinary = _config.UseBinary;             // 바이너리 모드 사용 여부 지정
            request.KeepAlive = false;                         // 업로드 후 연결을 유지하지 않음

            Stream requestStream = null; // FTP 서버로 데이터를 전송할 스트림 변수 선언

            try
            {
                // 취소 요청이 들어오면 예외 발생 (비동기 작업 취소 지원)
                cancellationToken.ThrowIfCancellationRequested();

                // FTP 서버로 데이터를 전송할 스트림을 비동기로 획득
                requestStream = await request.GetRequestStreamAsync().ConfigureAwait(false);

                // 데이터를 복사할 때 사용할 버퍼(1MB 크기) 생성
                byte[] buffer = new byte[1024 * 1024];
                int bytesRead; // 실제로 읽은 바이트 수를 저장할 변수

                ///
                /// 1) 먼저 메모리(byte[]) chunk를 FTP로 전송
                ///
                // memoryChunk를 읽기 전용 메모리 스트림으로 감싸서 사용
                using (var ms = new MemoryStream(memoryChunk, writable: false))
                {
                    // 메모리 스트림에서 데이터를 버퍼 단위로 읽어서 FTP 서버로 전송
                    while ((bytesRead = await ms.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
                                           .ConfigureAwait(false)) > 0)
                    {
                        // 읽은 만큼의 데이터를 FTP 서버로 전송
                        await requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken)
                                           .ConfigureAwait(false);
                    }
                }

                ///
                /// 2) 그 뒤 파일 chunk들을 순차적으로 이어붙임
                ///
                // chunkPaths에 있는 각 파일을 순서대로 처리
                foreach (var filePath in chunkPaths)
                {
                    // 취소 요청이 들어오면 예외 발생
                    cancellationToken.ThrowIfCancellationRequested();

                    // 파일이 실제로 존재하는지 확인, 없으면 예외 발생
                    if (!File.Exists(filePath))
                        throw new FileNotFoundException("Chunk file not found: " + filePath);

                    // 파일을 읽기 전용으로 스트림을 열어서 사용
                    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // 파일 스트림에서 데이터를 버퍼 단위로 읽어서 FTP 서버로 전송
                        while ((bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
                                                   .ConfigureAwait(false)) > 0)
                        {
                            // 읽은 만큼의 데이터를 FTP 서버로 전송
                            await requestStream.WriteAsync(buffer, 0, bytesRead, cancellationToken)
                                               .ConfigureAwait(false);
                        }
                    }
                }

                // 서버의 응답을 받아 업로드 성공 여부 확인
                using (var response = (FtpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
                {
                    // 필요시 response.StatusDescription을 통해 서버 응답 메시지 확인 가능
                }
            }
            finally
            {
                // FTP 서버로 데이터 전송 스트림 자원 해제 (메모리 누수 방지)
                if (requestStream != null)
                    requestStream.Dispose();
            }
        }
    }
}

FtpClientConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace FtpClient
{
    // FTP 접속 및 업로드 관련 설정 정보를 담는 클래스
    [Serializable]
    public class FtpClientConfig
    {
        // FTP 서버 주소 (예: "ftp.example.com")
        public string Host { get; set; }          // e.g. "ftp.example.com"
        // FTP 서버 포트 (기본값: 21)
        public int Port { get; set; } = 21;
        // FTP 로그인 사용자명
        public string Username { get; set; }
        // FTP 로그인 비밀번호
        public string Password { get; set; }

        /// <summary>
        /// FTP 서버의 루트 경로(옵션). 예: "/base/dir"
        /// </summary>
        public string BasePath { get; set; } = "/";

        /// <summary>
        /// FTPS(SSL) 사용 여부 (true면 SSL/TLS로 접속)
        /// </summary>
        public bool UseSsl { get; set; } = false;

        /// <summary>
        /// Passive 모드 사용 여부 (보통 true 권장, 방화벽 환경에서 유리)
        /// </summary>
        public bool UsePassive { get; set; } = true;

        /// <summary>
        /// Binary 모드 여부 (파일 업로드 시 보통 true)
        /// </summary>
        public bool UseBinary { get; set; } = true;

        // FTP 인증 정보를 NetworkCredential 객체로 반환
        public NetworkCredential ToCredential()
        {
            return new NetworkCredential(Username, Password);
        }

        // remotePath를 포함한 FTP 업로드용 URI를 생성
        public Uri BuildUri(string remotePath)
        {
            // remotePath가 null 또는 빈 문자열이면 예외 발생
            if (string.IsNullOrEmpty(remotePath))
                throw new ArgumentNullException(nameof(remotePath));

            // BasePath가 null/빈 문자열이면 기본값 "/" 사용
            string basePath = string.IsNullOrEmpty(BasePath) ? "/" : BasePath;
            // BasePath가 슬래시로 끝나지 않으면 슬래시 추가
            if (!basePath.EndsWith("/")) basePath += "/";

            // remotePath가 슬래시로 시작하면 제거 (중복 방지)
            if (remotePath.StartsWith("/"))
                remotePath = remotePath.Substring(1);

            // 최종 FTP URI 문자열 조합
            var uriString = $"ftp://{Host}:{Port}{basePath}{remotePath}";
            // Uri 객체로 반환
            return new Uri(uriString);
        }
    }
}

 

블로그 이미지

RIsN

,

사용 이유: 치트 및 테이블 다운로드가 우연히 빌드에서 실행되지 않도록 하기 위해

Conditional Compilation이라는 것은 컴파일러에게 "이 조건이 충족되면 이 코드를 컴파일해, 그렇지 않으면 무시해"라고 말하는 방법이야. 즉, 코드가 실제로 실행 파일에 포함될지 여부를 미리 정의하는 것이지!

조건부 컴파일은 여러 이유로 유용해:

  1. 플랫폼 별 코드: 안드로이드와 iOS, PC 등 다양한 플랫폼에서 동작해야 할 때 각 플랫폼에 맞는 코드만 컴파일할 수 있어.
  2. 디버깅: 개발 중에는 디버깅 코드가 필요하지만, 실제 릴리즈에서는 그런 코드를 빼고 싶을 때 사용해.
  3. 버전 관리: 예를 들어, 레거시 시스템과 새로운 시스템이 함께 동작해야 하는 경우, 조건부 컴파일을 이용해 구버전 코드와 신버전 코드를 분리할 수 있어.

C#과 Unity에서 많이 쓰이는 예시가 이런 것들이야:

#if UNITY_EDITOR
    // 에디터에서만 실행될 코드
#elif UNITY_ANDROID
    // 안드로이드에서만 실행될 코드
#elif UNITY_IOS
    // iOS에서만 실행될 코드
#endif

이렇게 하면, 해당 조건이 참인 경우에만 코드가 컴파일되고 실행되겠지. 😸🌟

많은 프로그래밍 언어가 이러한 조건부 컴파일을 지원해, 게임 개발뿐만 아니라 다양한 프로젝트에서도 쓸모있는 기능이야! 🎮💫

블로그 이미지

RIsN

,

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part2: 자료구조와 알고리즘

  • 기초를 다시 돌아보는 데 좋음
블로그 이미지

RIsN

,

[C#] IComparable

C# 2023. 5. 18. 13:33

C# 언어에서 IComparable 인터페이스는 오브젝트 간의 일반적인 정렬 순서를 제공하는 메서드를 정의합니다. 이 인터페이스를 사용하면 객체를 정렬할 수 있는 능력을 추가로 제공할 수 있습니다. 이는 배열 또는 리스트의 정렬 메서드와 같이, 순서가 필요한 상황에서 유용합니다.

IComparable 인터페이스는 단일 메서드 CompareTo를 정의하며, 이 메서드는 현재 인스턴스와 비교 대상이 되는 오브젝트를 매개변수로 받아들입니다.

public interface IComparable { 
	int CompareTo(object obj); 
}


CompareTo 메서드는 다음과 같이 동작합니다:

만약 현재 인스턴스가 매개변수로 제공된 오브젝트보다 "작을" 경우, 이 메서드는 음의 정수를 반환합니다.
만약 현재 인스턴스가 매개변수로 제공된 오브젝트와 "같을" 경우, 이 메서드는 0을 반환합니다.
만약 현재 인스턴스가 매개변수로 제공된 오브젝트보다 "클" 경우, 이 메서드는 양의 정수를 반환합니다.
따라서, IComparable을 구현하는 클래스를 작성할 때는 CompareTo 메서드를 통해 두 객체를 어떻게 비교할지 정의해야 합니다.

아래 예시는 Person 클래스가 IComparable 인터페이스를 구현하는 방법을 보여줍니다:

public class Person : IComparable {
	public string Name { get; set; } 
	public int CompareTo(object obj) { 
    	if (obj == null) return 1; 
        
        Person otherPerson = obj as Person; 
        if (otherPerson != null) return this.Name.CompareTo(otherPerson.Name); 
        else throw new ArgumentException("Object is not a Person");     
    } 
}


위 코드에서 Person 클래스의 CompareTo 메서드는 먼저 대상 오브젝트가 null인지 확인하고, 그 다음 대상 오브젝트가 Person 타입인지 확인합니다. 만약 대상 오브젝트가 Person이라면, 이 메서드는 string 타입의 Name 프로퍼티를 비교하여 결과를 반환합니다.

IComparable 인터페이스를 구현하면 Array.Sort()나 List.Sort() 등의 메서드를 사용하여 오브젝트를 쉽게 정렬할 수 있습니다.

블로그 이미지

RIsN

,
  • terminal에서 which dotnet으로 path 확인 후 넣기
    • 참고: path 마지막에 dotnet이 2번 들어갈 경우, 마지막 dotnet 폴더는 제거

 

블로그 이미지

RIsN

,

미로 생성 알고리즘

C# 2023. 2. 7. 09:18

Binary Tree 미로 생성 알고리즘

  • 오른쪽 방향으로 갈 지 아래 방향으로 갈 지를 랜덤으로 정함

Side Winder 미로 생성 알고리즘

  • 오른쪽 방향(한 방향)으로 가다가 아래 방향(다른 방향)으로 가야 하는 경우가 생기면 오른쪽으로 움직인 곳 중 랜덤으로 한 곳에서 정해서 감

참고 사이트: https://errorcode1001.tistory.com/9

'C#' 카테고리의 다른 글

[C#] IComparable  (0) 2023.05.18
[VSCode: Error] Mac OS에서 FSharp Path 에러 생길 때  (0) 2023.05.09
Javascript의 getInt16()를 C#으로 Convert  (0) 2022.12.20
GetHashCode  (0) 2021.04.23
백준 1193 : 분수찾기  (0) 2021.02.03
블로그 이미지

RIsN

,

Code

private short ByteToInt16(byte[] _byte, bool _littleEndian = false) {
    if(_littleEndian) {
        return (short)(_byte[0] | _byte[1] << 8);
    } else {
        return (short)(_byte[1] | _byte[0] << 8);
    }
}
private ushort ByteToUInt16(byte[] _byte, bool _littleEndian = false) {
    if(_littleEndian) {
        return (ushort)(_byte[0] | _byte[1] << 8);
    } else {
        return (ushort)(_byte[1] | _byte[0] << 8);
    }
}
  • Little Endian
    • Byte 저장 순서에 관한 것으로 낮은 바이트를 낮은 주소에 넣는다.
      • 반대는 Big Endian
      • 엔디언(Endian)이라는 용어가 나오는데, 이건 조너선 스위프트의 작품인 《걸리버 여행기》에서 유래한 단어다. 작중 릴리퍼트라는 난쟁이들이 사는 나라에서 달걀을 먹을 때 뭉툭한 끝을 깨먹은 사람들과 뾰족한 끝을 깨먹는 사람들이 자기들이 옳다며 논쟁을 벌이는데, 여기서 뭉툭한 끝을 깨먹는 사람들을 큰 끝(big end)을 깨먹는다고 ian을 붙여 big endian이라고 부르고, 반대의 경우를 작은 끝(little end)을 깨먹는다고 little endian이라고 부른다.
  • | or 연산
  • << 왼쪽 시프트 연산

P.S. getInt24()의 경우

private int ByteToInt24(byte[] _byte, bool _littleEndian = false) {
    if(_littleEndian) {
        return (int)(_byte[0] | _byte[1] << 8 | _byte[2] << 16);
    } else {
        return (int)(_byte[2] | _byte[1] << 8 | _byte[0] << 16);
    }
}
private uint ByteToUInt24(byte[] _byte, bool _littleEndian = false) {
    if(_littleEndian) {
        return (uint)(_byte[0] | _byte[1] << 8 | _byte[2] << 16);
    } else {
        return (uint)(_byte[2] | _byte[1] << 8 | _byte[0] << 16);
    }
}

'C#' 카테고리의 다른 글

[VSCode: Error] Mac OS에서 FSharp Path 에러 생길 때  (0) 2023.05.09
미로 생성 알고리즘  (0) 2023.02.07
GetHashCode  (0) 2021.04.23
백준 1193 : 분수찾기  (0) 2021.02.03
백준 2292 : 벌집  (0) 2021.02.02
블로그 이미지

RIsN

,

문제

베르트랑 공준은 임의의 자연수 n에 대하여, n보다 크고, 2n보다 작거나 같은 소수는 적어도 하나 존재한다는 내용을 담고 있다.

이 명제는 조제프 베르트랑이 1845년에 추측했고, 파프누티 체비쇼프가 1850년에 증명했다.

예를 들어, 10보다 크고, 20보다 작거나 같은 소수는 4개가 있다. (11, 13, 17, 19) 또, 14보다 크고, 28보다 작거나 같은 소수는 3개가 있다. (17,19, 23)

자연수 n이 주어졌을 때, n보다 크고, 2n보다 작거나 같은 소수의 개수를 구하는 프로그램을 작성하시오. 


입력

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 케이스는 n을 포함하는 한 줄로 이루어져 있다.

입력의 마지막에는 0이 주어진다.


출력

각 테스트 케이스에 대해서, n보다 크고, 2n보다 작거나 같은 소수의 개수를 출력한다.


코드

using System;
					
public class Program
{
	public static void Main()
	{
		// :: 소수 저장소 등록
		bool[] primes = new bool[(123456*2) + 1];
		
		// :: 1은 소수가 아님
		primes[1] = true;
		
		// :: 소수 등록
		for(int index = 2; index <= primes.Length - 1; index++) {
			// :: Next : 소수가 아닐 때
			if(primes[index])
				continue;
			
			// :: 소수 계산 : 자기 자신의 배수를 소수가 아니라고 등록
			for(int indexA = index + index; indexA <= primes.Length - 1; indexA += index) {
				primes[indexA] = true;
			}
		}
		
		// :: 출력 선언
		string print = "";
		
		// :: 연산
		while(true) {
			int num = int.Parse(Console.ReadLine());
			
			// :: EXIT : 0이면 나가기
			if(num == 0) break;
						
			// :: Count 획득
			int count = 0;
			for(int index = num + 1; index <= num*2; index++) {
				if(!primes[index]) count += 1;
			}
			
			// :: 카운트 기록
			print += count + "\n";
		}
		
		// :: 출력
		Console.WriteLine(print);
	}
}

참고

'C# > Baekjoon' 카테고리의 다른 글

백준 1929 : 소수 구하기  (0) 2022.03.31
백준 11653 : 소인수분해  (0) 2022.03.30
백준 2581 : 소수  (0) 2022.03.29
백준 1978 : 소수 찾기  (0) 2022.03.28
백준 10757 : 큰 수 A+B  (0) 2022.03.25
블로그 이미지

RIsN

,

문제

M이상 N이하의 소수를 모두 출력하는 프로그램을 작성하시오.


입력

첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.


출력

한 줄에 하나씩, 증가하는 순서대로 소수를 출력한다.


코드

using System;
using System.Text;
					
public class Program
{
	public static void Main()
	{
		// :: 입력 M, N
		string[] input = Console.ReadLine().Split(' ');
		
		// :: 변환 : M, N
		int numMin = int.Parse(input[0]);
		int numMax = int.Parse(input[1]);
		
		// :: 참고 : 에라토스테네스의 체
		// :: https://ko.wikipedia.org/wiki/%EC%97%90%EB%9D%BC%ED%86%A0%EC%8A%A4%ED%85%8C%EB%84%A4%EC%8A%A4%EC%9D%98_%EC%B2%B4
		
		// :: 배열 제작 : 기본값 false
		bool[] primes = new bool[numMax +1];
		primes[1] = true; // : 1 예외 처리
		
		// :: 소수가 아닌 것에 : true 처리
		for(int index = 2; index * index <= numMax; index++) {
			// :: 소수일 때
			if(!primes[index]) {
				// :: 초기값은 소수 * 소수
				// :: 증가값은 +소수
				for(int multiple = index + index; multiple <= numMax; multiple += index) {
					primes[multiple] = true;
				}
			}				
		}
		
		// :: 출력 확인
		StringBuilder print = new StringBuilder(); // : string을 쓸 경우 개행 문제인지, 메모리 초과가 뜸
		for(int index = numMin; index <= numMax; index++)  {
			if(!primes[index]) {
				//Console.WriteLine(index);
				print.Append(index + "\n");
			}
		}
		
		// :: 출력
		Console.WriteLine(print);
	}
}

참고

  • string
    • string은 값 타입이 아닌 참조 변수
    • 문자열을 조합할 때마다 새로운 클래스가 생성
    • 문자열을 조합할 때마다 부하가 발생
  • StringBuilder
    • 새로운 변수를 사용하지 않고 결합

사이트 : 생각대로 살지 않으면 사는대로 생각한다. :: [C#] string 과 StringBuilder 사용 (tistory.com)

'C# > Baekjoon' 카테고리의 다른 글

백준 4948 : 베르트랑 공준  (0) 2022.04.06
백준 11653 : 소인수분해  (0) 2022.03.30
백준 2581 : 소수  (0) 2022.03.29
백준 1978 : 소수 찾기  (0) 2022.03.28
백준 10757 : 큰 수 A+B  (0) 2022.03.25
블로그 이미지

RIsN

,

문제

정수 N이 주어졌을 때, 소인수분해하는 프로그램을 작성하시오.


입력

첫째 줄에 정수 N (1 ≤ N ≤ 10,000,000)이 주어진다.


출력

N의 소인수분해 결과를 한 줄에 하나씩 오름차순으로 출력한다. N이 1인 경우 아무것도 출력하지 않는다.


코드

using System;
					
public class Program
{
	public static void Main()
	{
		// :: 입력 : 소인수 분해할 것
		int num = int.Parse(Console.ReadLine());
		
		// :: EXIT : 1일 경우
		if(num == 1) return;
		
		// :: 소인수 분해
		string print = "";
		for(int index = 2; index <= num; index++) {
			// :: 0으로 나눠질 때
			if(num % index == 0) {
				// :: 나눈 것을 넣을 것
				num = num / index;

				// :: print에 소수 기록
				print += index.ToString();

				// :: 1이 되었으면 Break
				if(num == 1) {
					break;
				}
				// :: 아니면
				else {
					// :: 한줄 띄기 넣기
					print += "\n";
				}

				// :: 초기화
				index = 1;
			}
		}
		
		// :: 출력
		Console.WriteLine(print);
	}
	
	// :: 소수 구하기 : 이거 쓰면 시간 초과
	public static bool IsPrime(int num) {
		// :: 1이면 소수가 아님
		if(num == 1) return false;
		
		// :: 본래 수의 2를 나눈 것(제대로 이해는 안되지만, 반절까지)까지 나눴을 때 0이 되는 게 있는 지 확인
		for(int index = 2; index <= num / 2; index++) {
			if(num % index == 0) return false;
		}
		return true;
	}
}

 

'C# > Baekjoon' 카테고리의 다른 글

백준 4948 : 베르트랑 공준  (0) 2022.04.06
백준 1929 : 소수 구하기  (0) 2022.03.31
백준 2581 : 소수  (0) 2022.03.29
백준 1978 : 소수 찾기  (0) 2022.03.28
백준 10757 : 큰 수 A+B  (0) 2022.03.25
블로그 이미지

RIsN

,