πŸ“„ Get_Next_Line: β€˜μƒνƒœβ€™λ₯Ό κΈ°μ–΅ν•œλ‹€λŠ” κ²ƒμ˜ 의미

λ§Œμ•½ μ»΄ν“¨ν„°μ—κ²Œ 기얡이 μ—†λ‹€λ©΄ μ–΄λ–»κ²Œ 될까? λͺ¨λ“  연산은 κ·Έμ € μΌνšŒμ„±μœΌλ‘œ λλ‚˜κ³ , 방금 전에 ν–ˆλ˜ μž‘μ—…μ„ λ‹€μ‹œ μ΄μ–΄κ°€λŠ” 것은 λΆˆκ°€λŠ₯ν•  것이닀. libftκ°€ Cμ–Έμ–΄μ˜ 문법과 λ©”λͺ¨λ¦¬ μ‘°μž‘μ΄λΌλŠ” β€˜ν–‰μœ„β€™μ— μ§‘μ€‘ν•˜λŠ” κ³Όμ œμ˜€λ‹€λ©΄, get_next_line(μ΄ν•˜ GNL)은 컴퓨터가 μ–΄λ–»κ²Œ β€˜μƒνƒœ(state)’λ₯Ό κΈ°μ–΅ν•˜κ³  연속적인 μž‘μ—…μ„ μ²˜λ¦¬ν•˜λŠ”μ§€μ— λŒ€ν•œ κΉŠμ€ 톡찰을 μš”κ΅¬ν•˜λŠ”, μ™„μ „νžˆ μƒˆλ‘œμš΄ μ°¨μ›μ˜ λ„μ „μ΄μ—ˆλ‹€.

β€œνŒŒμΌμ—μ„œ ν•œ 쀄씩 μ½μ–΄μ˜€λΌβ€λŠ” λͺ…μ œλŠ” λ‹¨μˆœν•΄ λ³΄μ˜€λ‹€. ν•˜μ§€λ§Œ 이내 κΉ¨λ‹¬μ•˜λ‹€. 이것은 λ‹¨μˆœνžˆ νŒŒμΌμ„ μ½λŠ” κΈ°μˆ μ„ λ„˜μ–΄, β€˜μ‹œκ°„β€™μ΄λΌλŠ” μΆ• μœ„μ—μ„œ λ°μ΄ν„°μ˜ 흐름을 μ œμ–΄ν•˜κ³ , ν•¨μˆ˜μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό λ›°μ–΄λ„˜λŠ” β€˜κΈ°μ–΅β€™μ„ κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” λ¬Έμ œλΌλŠ” 것을. Cμ–Έμ–΄μ˜ μ €μˆ˜μ€€(low-level) 파일 μž…μΆœλ ₯κ³Ό μ”¨λ¦„ν•˜λ©°, staticμ΄λΌλŠ” ν‚€μ›Œλ“œμ— λ‹΄κΈ΄ 철학을 λΉ„λ‘œμ†Œ μ΄ν•΄ν•˜κ²Œ 된 μ—¬μ •μ΄μ—ˆλ‹€.

🧠 핡심 κ°œλ… μ •λ³΅ν•˜κΈ° (Conquering Core Concepts)

GNL의 μ„Έκ³„λ‘œ λ“€μ–΄κ°€κΈ° μœ„ν•΄μ„ , μ»΄ν“¨ν„°μ˜ κ°€μž₯ 기본적인 μ†Œν†΅ 방식을 λ¨Όμ € 이해해야 ν–ˆλ‹€.

1. 파일 λ””μŠ€ν¬λ¦½ν„°(File Descriptor): μΆ”μƒν™”μ˜ 첫걸음

μš°λ¦¬κ°€ ν‚€λ³΄λ“œλ₯Ό λ‘λ“œλ¦¬κ³ , λͺ¨λ‹ˆν„°λ₯Ό 보고, νŒŒμΌμ„ μ½λŠ” λͺ¨λ“  ν–‰μœ„λŠ” 운영체제(OS)의 λˆˆμ—λŠ” κ·Έμ € β€˜λ°μ΄ν„°μ˜ 흐름’일 뿐이닀. OSλŠ” 이 λ³΅μž‘ν•œ μž₯μΉ˜λ“€μ„ 0(ν‘œμ€€ μž…λ ₯), 1(ν‘œμ€€ 좜λ ₯), 2(ν‘œμ€€ μ—λŸ¬)와 같은 μ •μˆ˜ 번호둜 λ‹¨μˆœν™”ν•˜μ—¬ μš°λ¦¬μ—κ²Œ μ œκ³΅ν•œλ‹€. 이것이 λ°”λ‘œ 파일 λ””μŠ€ν¬λ¦½ν„°(FD)λ‹€. open() ν•¨μˆ˜λ₯Ό 톡해 νŒŒμΌμ„ μ—΄λ©΄, OSλŠ” μƒˆλ‘œμš΄ λ²ˆν˜Έν‘œλ₯Ό λ°œκΈ‰ν•˜λ©° β€œμž, 이제 이 번호둜 파일과 μ†Œν†΅ν•΄β€λΌκ³  λ§ν•΄μ£ΌλŠ” 것과 κ°™λ‹€. GNL은 이 λ²ˆν˜Έν‘œ ν•˜λ‚˜μ— μ˜μ§€ν•΄ κ±°λŒ€ν•œ 파일의 λ‚΄μš©μ„ ν•œ 쀄씩 νƒν—˜ν•˜λŠ” 항해사와 κ°™μ•˜λ‹€.

2. read()와 BUFFER_SIZE: 경계 μœ„μ˜ 쀄타기

GNL의 μœ μΌν•œ λ¬΄κΈ°λŠ” read ν•¨μˆ˜μ˜€λ‹€. 이 ν•¨μˆ˜λŠ” BUFFER_SIZEλΌλŠ” μ •ν•΄μ§„ 크기만큼만 데이터λ₯Ό κ°€μ Έμ˜¨λ‹€. μ—¬κΈ°μ„œ GNL의 본질적인 λ”œλ ˆλ§ˆκ°€ μ‹œμž‘λœλ‹€. μš°λ¦¬κ°€ μ½μœΌλ €λŠ” β€˜ν•œ μ€„β€™μ΄λΌλŠ” κ°œλ…μ€ μ§€κ·Ήνžˆ 인간적인 λ‹¨μœ„μ΄μ§€λ§Œ, μ»΄ν“¨ν„°λŠ” κ·Έμ € λ°”μ΄νŠΈ(byte)의 νλ¦„μœΌλ‘œ 세상을 λ³Έλ‹€.

  • BUFFER_SIZEκ°€ ν•œ 쀄보닀 μž‘μœΌλ©΄, κ°œν–‰ 문자(\n)λ₯Ό λ§Œλ‚  λ•ŒκΉŒμ§€ μ—¬λŸ¬ 번 readλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€.
  • BUFFER_SIZEκ°€ ν•œ 쀄보닀 크면, ν•œ 쀄을 읽고도 데이터가 버퍼에 λ‚¨λŠ”λ‹€.

λ°”λ‘œ 이 β€˜λ‚¨μ•„λ²„λ¦° 데이터’λ₯Ό μ–΄λ–»κ²Œ μ²˜λ¦¬ν•  것인가? 이번 ν˜ΈμΆœμ—μ„œ 남은 데이터λ₯Ό λ‹€μŒ ν˜ΈμΆœμ„ μœ„ν•΄ μ–΄λ”˜κ°€μ— 고이 λ³΄κ΄€ν•΄λ‘μ–΄μ•Όλ§Œ ν–ˆλ‹€. ν•¨μˆ˜κ°€ 호좜되고 λλ‚˜λŠ” μ°°λ‚˜μ˜ μˆœκ°„μ„ λ„˜μ–΄, λ‹€μŒμ„ κΈ°μ•½ν•˜λŠ” β€˜κΈ°μ–΅β€™μ΄ ν•„μš”ν–ˆλ‹€.

3. λ§ˆλ²•μ˜ ν‚€μ›Œλ“œ, static: ν•¨μˆ˜μ— μ˜ν˜Όμ„ λΆˆμ–΄λ„£λ‹€

이 문제의 해닡은 λ°”λ‘œ static λ³€μˆ˜μ— μžˆλ‹€. ✨

char *get_next_line(int fd)
{
    static char *backup;
    // ...
}

ν•¨μˆ˜κ°€ λλ‚˜λ©΄ μ‚¬λΌμ§€λŠ” 일반 μ§€μ—­ λ³€μˆ˜μ™€ 달리, static λ³€μˆ˜λŠ” ν”„λ‘œκ·Έλž¨μ΄ μ‹œμž‘λ  λ•Œ 단 ν•œ 번 λ©”λͺ¨λ¦¬μ— ν• λ‹Ήλ˜μ–΄ ν”„λ‘œκ·Έλž¨μ΄ 끝날 λ•ŒκΉŒμ§€ μžμ‹ μ˜ 값을 μœ μ§€ν•œλ‹€. 즉, GNL ν•¨μˆ˜κ°€ μˆ˜μ‹­, 수백 번 ν˜ΈμΆœλ˜μ–΄λ„ backup λ³€μˆ˜λŠ” 마치 μ–΄μ œμ˜ 일을 κΈ°μ–΅ν•˜λŠ” μ‚¬λžŒμ²˜λŸΌ, 이전에 읽고 남겨둔 데이터λ₯Ό κ°„μ§ν•˜κ³  μžˆλŠ” 것이닀.

이 static λ³€μˆ˜ backup에 read둜 μ½μ–΄μ˜¨ λ‚΄μš©μ„ 계속 이어 뢙이고(strjoin), κ°œν–‰ 문자λ₯Ό λ°œκ²¬ν•˜λ©΄ κ·Έ μ•žλΆ€λΆ„κΉŒμ§€λ₯Ό 세상에 내보내고(return), backupμ—λŠ” κ°œν–‰ 문자 λ’€μ˜ λ‚˜λ¨Έμ§€ 약속을 λ‹΄μ•„λ‘λŠ” 것. 이 λ‘œμ§μ„ κΉ¨λ‹¬μ•˜μ„ λ•Œ, λ‚˜λŠ” λΉ„λ‘œμ†Œ ν•¨μˆ˜μ—μ„œ μ•„μ£Ό 기본적인 β€˜μƒνƒœβ€™λΌλŠ” κ±Έ λ³΄κ΄€ν•˜λŠ” 방법을 배울 수 μžˆμ—ˆλ‹€.

πŸ› οΈ λ‚˜μ˜ GNL κ΅¬ν˜„κΈ° (My GNL Implementation Journey)

κ·ΈλŸ¬λ‚˜ μ•Œλ‹€μ‹œν”Ό 머리둜 μ΄ν•΄ν•˜λŠ” 것과 μ†μœΌλ‘œ κ΅¬ν˜„ν•˜λŠ” 것은 μ²œμ§€ 차이닀.

  1. 읽고, μŒ“κ³ , 또 μŒ“κ³ : read ν•¨μˆ˜κ°€ 더 이상 읽을 것이 없을 λ•ŒκΉŒμ§€, λ˜λŠ” κ°œν–‰μ„ λ§Œλ‚  λ•ŒκΉŒμ§€ λ°˜λ³΅λ¬Έμ„ λŒμ•˜λ‹€. backupμ΄λΌλŠ” 곡간에 BUFFER_SIZE만큼의 λ²½λŒμ„ κ³„μ†ν•΄μ„œ μŒ“μ•„ μ˜¬λ¦¬λŠ” κ³Όμ •μ΄μ—ˆλ‹€. 이 κ³Όμ •μ—μ„œ ft_strjoin은 λ‚˜μ˜ λ“ λ“ ν•œ μ‹œλ©˜νŠΈκ°€ λ˜μ–΄μ£Όμ—ˆλ‹€.
  2. 자λ₯΄κ³ , 내보내고: λ§ˆμΉ¨λ‚΄ κ°œν–‰μ΄λΌλŠ” μ΄μ •ν‘œλ₯Ό λ§Œλ‚˜λ©΄, κ·Έκ³³κΉŒμ§€μ˜ 길을 μž˜λΌλ‚΄μ–΄ 결과둜 λ°˜ν™˜ν•œλ‹€.
  3. κΈ°μ–΅ν•˜κ³ , μ€€λΉ„ν•˜κ³ : 그리고 κ°€μž₯ μ€‘μš”ν–ˆλ˜ 단계. backup λ³€μˆ˜μ—λŠ” μž˜λΌλ‚΄κ³  남은 λ‚˜λ¨Έμ§€ 뢀뢄을 λ‹΄μ•„, λ‹€μŒ 호좜의 μ‹œμž‘μ μ΄ 될 수 μžˆλ„λ‘ μ€€λΉ„μ‹œμΌ°λ‹€. 이 κ³Όμ •μ—μ„œ μˆ˜μ—†μ΄ ν„°μ Έ λ‚˜μ˜€λŠ” λ©”λͺ¨λ¦¬ λˆ„μˆ˜(leak)λ₯Ό 막기 μœ„ν•΄ free와 μ‚¬νˆ¬λ₯Ό λ²Œμ˜€λ‹€. 정말 이 λΆ€λΆ„μ—μ„œ 생길 수 μžˆλŠ” μ—λŸ¬, 특히 λ°˜λ³΅λ˜λŠ”λ° λ‚΄κ°€ λ†“μΉ˜μ§€ μ•ŠμœΌλ €λ©΄ ꡬ쑰적으둜 생각해야 ν–ˆκ³ , Cμ–Έμ–΄κ°€ μ™œ 그토둝 μ •κ΅ν•œ λ©”λͺ¨λ¦¬ 관리λ₯Ό μš”κ΅¬ν•˜λŠ”μ§€ 온λͺΈμœΌλ‘œ κΉ¨λ‹¬μ•˜λ‹€. (정말이지, 세그폴 화면은 λ‹€μ‹œ 보고 μ‹Άμ§€ μ•Šλ‹€β€¦ πŸ˜‡)

✨ λ³΄λ„ˆμŠ€: μ—¬λŸ¬ 개의 기얡을 λ™μ‹œμ— (Bonus: Multiple States at Once!)

ν•„μˆ˜ 파트의 GNL은 static λ³€μˆ˜ ν•˜λ‚˜μ— μ˜μ‘΄ν•˜κΈ°μ—, 였직 ν•˜λ‚˜μ˜ κΈ°μ–΅(파일)만 μœ μ§€ν•  수 μžˆμ—ˆλ‹€. ν•˜μ§€λ§Œ λ³΄λ„ˆμŠ€ νŒŒνŠΈλŠ” μ—¬λŸ¬ νŒŒμΌμ„ λ™μ‹œμ— μ—΄κ³ , 각 파일의 읽기 μƒνƒœλ₯Ό λ…λ¦½μ μœΌλ‘œ κΈ°μ–΅ν•˜λΌλŠ” 더 높은 μ°¨μ›μ˜ 과제λ₯Ό μ œμ‹œν–ˆλ‹€.

ν•˜λ‚˜μ˜ λ‡Œλ‘œλŠ” μ—¬λŸ¬ μ‚¬λžŒμ˜ 기얡을 λ™μ‹œμ— 관리할 수 μ—†λ“―, static λ³€μˆ˜ ν•˜λ‚˜λ‘œλŠ” λΆ€μ‘±ν–ˆλ‹€. 해결책은 β€˜κΈ°μ–΅μ˜ λͺ©λ‘β€™μ„ λ§Œλ“œλŠ” 것이닀.

파일 λ””μŠ€ν¬λ¦½ν„°(FD)λ₯Ό μ—΄μ‡  μ‚Όμ•„, 각 열쇠에 λ§žλŠ” backup 데이터λ₯Ό μ €μž₯ν•˜λŠ” λ°°μ—΄(static char *backup[OPEN_MAX])μ΄λ‚˜ μ—°κ²° 리슀트λ₯Ό ν™œμš©ν–ˆλ‹€.

GNL이 νŠΉμ • fd와 ν•¨κ»˜ 호좜되면, μš°λ¦¬λŠ” κΈ°μ–΅μ˜ λͺ©λ‘μ—μ„œ ν•΄λ‹Ή fd에 λ§žλŠ” 기얡을 κΊΌλ‚΄ μž‘μ—…μ„ μ΄μ–΄κ°„λ‹€λŠ” 것을 ꡬ쑰화 ν•˜λŠ” 것이 κ΄€κ±΄μ΄μ—ˆλ‹€.

πŸ€” μ„±μ°° 및 배운 점 (Reflection & Lessons Learned)

GNL은 λ‚˜μ—κ²Œ β€˜λ³΄μ΄μ§€ μ•ŠλŠ” 것을 λ‹€λ£¨λŠ” 법’을 κ°€λ₯΄μ³μ€¬λ‹€.

  • μƒνƒœ κ΄€λ¦¬μ˜ 본질: 파일 μž…μΆœλ ₯을 λ„˜μ–΄, β€˜μƒνƒœβ€™λΌλŠ” 좔상적인 κ°œλ…μ„ μ–΄λ–»κ²Œ μ½”λ“œ λ ˆλ²¨μ—μ„œ κ΅¬μ²΄ν™”ν•˜κ³  μœ μ§€ν•˜λŠ”μ§€ 깊이 μ΄ν•΄ν•˜κ²Œ λ˜μ—ˆλ‹€. μ΄λŠ” λ‚˜μ€‘μ— μ›Ή μ„œλ²„κ°€ μˆ˜λ§Žμ€ ν΄λΌμ΄μ–ΈνŠΈμ˜ μ—°κ²° μƒνƒœλ₯Ό κΈ°μ–΅ν•˜κ±°λ‚˜, UI ν”„λ ˆμž„μ›Œν¬κ°€ μ»΄ν¬λ„ŒνŠΈμ˜ 이전 μƒνƒœλ₯Ό κΈ°μ–΅ν•˜λŠ” λ“± λͺ¨λ“  ν”„λ‘œκ·Έλž˜λ°μ˜ 근간이 λ˜λŠ” μ›λ¦¬μ˜€λ‹€. μ΄μ œλŠ” 정말 λ‹€μ–‘ν•œ λ„κ΅¬λ‚˜, κ°œλ…μ΄ 있고, 사싀 쑰금 더 곰곰히 생각해보면 β€˜static’이 내뢀에 λ‹Ήμ—°νžˆ λ…Ήμ•„ μžˆκ² μ§€λ§Œ, μ΄μ œλŠ” λ‹€μ†Œ ꡬ식(….) λ°©λ²•μž„μ„ μƒˆμ‚Ό λŠλΌκΈ΄ν•œλ‹€. κ·ΈλŸ¬λ‚˜ κ²°κ΅­ μ΅œμ ν™”κ°€ ν•„μš”ν•˜κ³ , 데이터λ₯Ό 더 κ³ μ†μœΌλ‘œ, 더 λΉ λ₯΄κ²Œ μ²˜λ¦¬ν•΄μ•Όν•œλ‹€λ©΄ μ–΄μ©Œλ©΄ λ‹€μ‹œ 끄집어낼 κΈ°νšŒκ°€ μ˜€μ§€ μ•Šμ„κΉŒ, κ·Έλ ‡κ²Œ 생각해본닀.
  • static의 μ² ν•™: static은 λ‹¨μˆœν•œ Cμ–Έμ–΄μ˜ ν‚€μ›Œλ“œκ°€ μ•„λ‹ˆμ—ˆλ‹€. ν•¨μˆ˜μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό μ΄ˆμ›”ν•˜μ—¬ 데이터λ₯Ό λ³΄μ‘΄ν•˜λŠ”, Cμ–Έμ–΄κ°€ μ œκ³΅ν•˜λŠ” κ°€μž₯ μ›μ‹œμ μ΄λ©΄μ„œλ„ κ°•λ ₯ν•œ μƒνƒœ 관리 λ„κ΅¬μž„μ„ κΉ¨λ‹¬μ•˜λ‹€. κ·Έλ•ŒλŠ” μ–Όλ§ˆλ‚˜ λΉ λ₯Έκ°€? 이걸 기반으둜 κ½€λ‚˜ ν˜Έλ“€κ°‘μ„ λ–¨μ—ˆλ˜(…) 기얡이 λ‚œλ‹€.
  • λ””λ²„κΉ…κ³Όμ˜ μ²˜μ ˆν•œ μ‚¬νˆ¬: 끝없이 ν„°μ§€λŠ” λ©”λͺ¨λ¦¬ λˆ„μˆ˜μ™€ 세그폴은 λ‚˜λ₯Ό μ’Œμ ˆμ‹œμΌ°μ§€λ§Œ, λ™μ‹œμ— λ©”λͺ¨λ¦¬μ˜ ν• λ‹Ήκ³Ό ν•΄μ œμ˜ 흐름을 μ§‘μš”ν•˜κ²Œ μΆ”μ ν•˜λŠ” 인내심과 문제 ν•΄κ²° λŠ₯λ ₯을 κΈΈλŸ¬μ£Όμ—ˆλ‹€. 그게 핡심이기도 ν–ˆλ‹€. 특히 λ³΄λ„ˆμŠ€λ₯Ό ν•˜κ²Œ 되면, FD 의 관리가 λ³‘λ ¬λ‘œ μ§„ν–‰λ˜λŠ”λ°, 쑰건이 좔가될 수둝 λ‹Ήμ—°νžˆ κΈ°μ‘΄ λ‚΄μš©μ„ 두고, λ‹€λ₯Έ λ‚΄μš©μ„ μ°Ύμ•„μ˜¨λ‹€λŠ” μž‘μ—…μ΄ μ΄μ œλŠ” 머릿속에 그렀지기에 μ–΄λ””μ„œ 뭘 μž‘μ•„μ•Ό ν•˜λŠ”κ°€? λ₯Ό κΈ°μ–΅ν•˜μ§€λ§Œ, 그땐 정말 νž˜λ“€μ—ˆλ‹€.

get_next_line은 ν•œ μ€„μ˜ λ¬Έμž₯을 읽어낸닀라고 μ‰½κ²Œ 이야긴 ν–ˆμ§€λ§Œ, 핡심은 μƒνƒœλ₯Ό μ €μž₯ν•˜κ³ , μ–΄λ–€ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ 거치고, 또 κ±°κΈ°μ„œ μ—¬λŸ¬ νŒŒμΌμ„ 닀룬닀면 μ–΄λ–€ κ³Όμ •μœΌλ‘œ μž‘μ—…μ„ μ™”λ‹€ κ°”λ‹€ ν•  수 μžˆλŠ”μ§€, κ·Έ 논리적 둜직이 λ­”μ§€λ₯Ό μ‹€μ§ˆμ μœΌλ‘œ λ°°μš°λŠ” κΈ°νšŒμ˜€λ‹€κ³  μƒκ°ν•œλ‹€.