C
C) C언어로 회원가입/로그인 시스템 구현하기!
sunwookim05
2023. 3. 19. 00:22
얼마 전 친구들이 디코에서 회원가입/로그인 시스템을 만들고 있길래 재밌어 보여서 C로 만들어 봤다.
https://github.com/sunwookim05/Member-management-system
GitHub - sunwookim05/Member-management-system
Contribute to sunwookim05/Member-management-system development by creating an account on GitHub.
github.com
먼저 main.h 를 만든다 모든 코드의 베이스가 됄 코드이다.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#pragma once
#ifndef __MAIN_H
#define __MAIN_H
#define import extern
#define final const
#define null NULL
#define false 0
#define true 1
typedef char *String;
typedef char byte;
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char ubyte;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef uint8_t boolean;
#pragma warning(pop)
#endif
그리고 전에 만들었던 Scanner-with-C 를 활용하고 싶어 Scanner와 System 클래스를 구현했다.
System.h
#include "main.h"
#pragma once
#ifndef __SYSTEM_H
#define __SYSTEM_H
struct __stdin_t;
#pragma pack(push, 1)
/**
* The {@code System} class contains several useful class fields
* and methods. It cannot be instantiated.
*
* Among the facilities provided by the {@code System} class
* are standard input, standard output, and error output streams;
* access to externally defined properties and environment
* variables; a means of loading files and libraries; and a utility
* method for quickly copying a portion of an array.
*
* @since 1.0
*/
typedef struct _System{
struct __stdout_t{
/**
* @brief System out print function
* @param format
* @return void
*/
void (*print)(const String, ...);
/**
* @brief System out println function
* @param format
* @return void
*/
void (*println)(const String, ...);
}out;
struct __stdin_t{
int (*read)();
} in;
}SYSTEM;
#pragma pack(pop)
#pragma warning(pop)
#endif
Scanner.h
#include "main.h"
#pragma once
#ifndef __Scanner_H
#define __Scanner_H
struct __stdin_t;
#pragma pack(push, 1)
/**
* @brief Scanner class
*/
typedef struct Scanner{
/**
* @brief User input char
* @param void
* @return char
*/
char (*nextChar)(void);
/**
* @brief User input Byte
* @param void
* @return byte
*/
byte (*nextByte)(void);
/**
* @brief User input Short
* @param void
* @return int16_t
*/
int16_t (*nextShort)(void);
/**
* @brief User input Int
* @param void
* @return int32_t
*/
int32_t (*nextInt)(void);
/**
* @brief User input Long
* @param void
* @return int64_t
*/
int64_t (*nextLong)(void);
/**
* @brief User input Unsigned Byte
* @param void
* @return ubyte
*/
ubyte (*nextUByte)(void);
/**
* @brief User input Unsigned Short
* @param void
* @return uint16_t
*/
uint16_t (*nextUShort)(void);
/**
* @brief User input Unsigned Int
* @param void
* @return uint32_t
*/
uint32_t (*nextUInt)(void);
/**
* @brief User input Unsigned Long
* @param void
* @return uint64_t
*/
uint64_t (*nextULong)(void);
/**
* @brief User input boolean
* @param void
* @return boolean
*/
boolean (*nextBoolean)(void);
/**
* @brief User input Float
* @param void
* @return float
*/
float (*nextFloat)(void);
/**
* @brief User input Double
* @param void
* @return double
*/
double (*nextDouble)(void);
/**
* @brief User input Long Double
* @param void
* @return long double
*/
long double (*nextLDouble)(void);
/**
* @brief User input String no Spaces
* @param void
* @return String
*/
String (*next)(void);
/**
* @brief User input String with Spaces
* @param void
* @return String
*/
String (*nextLine)(void);
}Scanner;
#pragma pack(pop)
Scanner new_Scanner(struct __stdin_t);
#pragma warning(pop)
#endif
Systemout.c
#include "main.h"
#include "System.h"
void print(const String format, ...) {va_list ap;char buf[4096];va_start(ap, format);vsprintf(buf, format, ap);va_end(ap);fprintf(stdout, "%s", buf);}
void println(const String format, ...) {va_list ap;char buf[4096];va_start(ap, format);vsprintf(buf, format, ap);va_end(ap);fprintf(stdout, "%s\n", buf);}
SYSTEM System = {print, println};
Scanner.c
#include "main.h"
#include "System.h"
#include "Scanner.h"
char nextChar(void){
char c;
scanf("%c", &c);
getchar();
return c;
}
int8_t nextByte(void){
int8_t b;
scanf("%hhd", &b);
getchar();
return b;
}
int16_t nextShort(void){
int16_t s;
scanf("%hd", &s);
getchar();
return s;
}
int32_t nextInt(void){
int32_t i;
scanf("%d", &i);
getchar();
return i;
}
int64_t nextLong(void){
int64_t l;
scanf("%lld", &l);
getchar();
return l;
}
uint8_t nextUByte(void){
uint8_t b;
scanf("%hhu", &b);
getchar();
return b;
}
uint16_t nextUShort(void){
uint16_t s;
scanf("%hu", &s);
getchar();
return s;
}
uint32_t nextUInt(void){
uint32_t i;
scanf("%u", &i);
getchar();
return i;
}
uint64_t nextULong(void){
uint64_t l;
scanf("%llu", &l);
getchar();
return l;
}
boolean nextBoolean(void){
String s = (String)calloc(0, sizeof(char) * 5);
scanf("%s", s);
if(atoi(s)|| !strncmp(s, "true", 4) || !strncmp(s, "True", 4) || !strncmp(s, "TRUE", 4)){
free(s);
return true;
}else{
free(s);
return false;
}
}
float nextFloat(void){
float f;
scanf("%f", &f);
getchar();
return f;
}
double nextDouble(void){
double d;
scanf("%lf", &d);
getchar();
return d;
}
long double nextLDouble(void){
long double ld;
scanf("%Lf", &ld);
getchar();
return ld;
}
String next(void){
String s = (String)calloc(0, sizeof(char) * 4096);
scanf("%s", s);
s = (String)realloc(s, sizeof(char) * (strlen(s) + 1));
getchar();
return s;
}
String nextLine(void){
String s = (String)calloc(0, sizeof(char) * 4096);
scanf("%[^\n]", s);
getchar();
return s;
}
/**
* Constructs a new {@code Scanner} that produces values scanned
* from the specified input stream. Bytes from the stream are converted
* into characters using the underlying platform's
*
* @param source An input stream to be scanned
*/
Scanner new_Scanner(struct __stdin_t source){
Scanner scanner = {
.nextChar = nextChar,
.nextByte = nextByte,
.nextShort = nextShort,
.nextInt = nextInt,
.nextLong = nextLong,
.nextUByte = nextUByte,
.nextUShort = nextUShort,
.nextUInt = nextUInt,
.nextULong = nextULong,
.nextBoolean = nextBoolean,
.nextFloat = nextFloat,
.nextDouble = nextDouble,
.nextLDouble = nextLDouble,
.next = next,
.nextLine = nextLine
};
return scanner;
}
다음으론 User 의 정보를 저장하고 처리할 수 있는 User 클래스를 구현하기 위해 User.h 와 User.c 를 만들었다.
User.h
#include "main.h"
#pragma once
#ifndef __User_H
#define __User_H
typedef struct __USERDATA__{
String id;
String password;
}USERDATA;
typedef struct __USERS__{
void (*writeLog)(uint8_t, USERDATA, FILE *);
boolean (*logout)(USERDATA *);
boolean (*signup)(USERDATA *, FILE *);
boolean (*login)(USERDATA *, FILE *);
}USERS;
typedef enum __MENU__{
SIGNUP = 1, LOGIN, LOGOUT, USERINFO, EXIT
}__MENU__;
typedef uint8_t MENU;
USERS new_User();
USERDATA new_UserData();
void delete_UserData(USERDATA *);
#pragma warning(pop)
#endif
User.c
#include "User.h"
#include "System.h"
#include "Scanner.h"
import SYSTEM System;
void delete_UserData(USERDATA *info){
free(info->id);
free(info->password);
}
void writeLog(uint8_t logCate, USERDATA info, FILE *fp){
String logCateStr[3] = {"SIGNUP", "LOGIN", "LOGOUT"};
time_t t = time(NULL);
struct tm tm = *localtime(&t);
fp = fopen("log.txt", "a");
fprintf(fp, "%d-%d-%d %d:%d:%d %s\nID: %s\nPassword: %s\n\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, logCateStr[logCate - 1], info.id, info.password);
fclose(fp);
}
boolean signup(USERDATA *info, FILE *fp){
Scanner sc = new_Scanner(System.in);
fp = fopen("user.txt", "r");
System.out.println("Sign up");
System.out.print("ID: ");
info->id = sc.next();
System.out.print("Password: ");
info->password = sc.next();
USERDATA user = new_UserData();
while (fscanf(fp, "%s", user.id) != EOF){
if(!strcmp(info->id, user.id)){
delete_UserData(&user);
return false;
}
}
delete_UserData(&user);
fclose(fp);
fp = fopen("user.txt", "a");
fprintf(fp, "%s %s\n", info->id, info->password);
fclose(fp);
return true;
}
boolean login(USERDATA *user, FILE *fp){
Scanner sc = new_Scanner(System.in);
fp = fopen("user.txt", "r");
System.out.println("Login");
System.out.print("ID: ");
user->id = sc.next();
System.out.print("Password: ");
user->password = sc.next();
USERDATA info = new_UserData();
while (fscanf(fp, "%s %s", info.id, info.password) != EOF){
if(!strcmp(user->id, info.id) && !strcmp(user->password, info.password)){
delete_UserData(&info);
fclose(fp);
return true;
}
}
fclose(fp);
delete_UserData(&info);
return false;
}
boolean logout(USERDATA *info){
Scanner sc = new_Scanner(System.in);
System.out.print("Do you want to logout? (y/n): ");
char bf = sc.nextChar();
if(bf == 'y' | 'Y'){
info->id = NULL;
info->password = NULL;
delete_UserData(info);
System.out.println("Logout success");
return true;
}else{
System.out.println("Logout failed");
return false;
}
}
USERS new_User(){
USERS user;
user.logout = logout;
user.signup = signup;
user.login = login;
user.writeLog = writeLog;
return user;
}
USERDATA new_UserData(){
USERDATA info;
info.id = (String)calloc(0, sizeof(char) * 20);
info.password = (String)calloc(0, sizeof(char) * 20);
return info;
}
마지막으로 클래스들을 활용하여 호출할 메인 클레스를 만든다.
main.c
#include "main.h"
#include "System.h"
#include "Scanner.h"
#include "User.h"
import SYSTEM System;
int main(void){
Scanner sc = new_Scanner(System.in);
USERS users = new_User();
USERDATA user = new_UserData();
FILE *fp;
boolean isSignup = false;
boolean isLogin = false;
boolean isLogout = true;
MENU menu = 0;
while (true){
System.out.print("Select menu\n1. Sign up\n2. Login\n3. Logout\n4. LOGININFO\n5. EXIT\n");
menu = sc.nextUByte();
if(menu == SIGNUP){
isSignup = users.signup(&user, fp);
System.out.println(isSignup ? "Sign up success" : "Sign up failed");
if (isSignup) users.writeLog(SIGNUP, user, fp);
}else if(menu == LOGIN){
if(isLogin){
System.out.println("Already login");
}else{
isLogin = users.login(&user, fp);
System.out.println(isLogin ? "Login success" : "Login failed");
users.writeLog(LOGIN, user, fp);
}
}else if(menu == LOGOUT){
if(!isLogin){
System.out.println("Already logout");
}else{
users.writeLog(LOGOUT, user, fp);
isLogout = users.logout(&user);
if(isLogout) isLogin = false;
}
}else if(menu == USERINFO){
if(isLogin) System.out.println("ID: %s\nPassword: %s", user.id, user.password);
else System.out.println("Please login");
}else if(menu == EXIT){
break;
}else{
System.out.println("Wrong menu");
}
}
delete_UserData(&user);
return 0;
}
콘솔에 이렇게 입력하면 실행이 된다.
gcc -c src\main.c -I inc\
gcc -c src\Scanner.c -I inc\
gcc -c src\Systemout.c -I inc\
gcc -c src\User.c -I inc\
gcc -o main main.o Scanner.o Systemout.o User.o
.\main