2017년 5월 22일 월요일
MP3 파일 ID3 태그 정리기 + 중복곡 검사기(torrent,billboard,albumart,앨범아트)
안녕하세요.
블로그 개설하고 처음 만든 프로그램이네요.
오늘 소개드릴 프로그램은 ID3 태그 정리기입니다.
사용법입니다.
1. 프로그램 실행 후 browse 버튼을 눌러 mp3파일이 든 폴더 불러오기
2. trim mp3 버튼을 눌러서 id3 태그 정리하기
(정리 방식 : 앨범명을 제목명으로 수정, 파일명을 "제목 - 가수.mp3" 로 수정)
깔끔하게 정리됩니다.
3. delete duplicated songs 버튼을 누르고 새 창이 뜨면 check 버튼 클릭!
(문자열 유사도를 검사해서 비슷한 제목의 곡을 추려냅니다.)
4. 추려진 곡 중 중복된 곡을 잘 보고 찾아서 모두 선택한 후 delete 버튼으로 삭제합니다.
끝~
가지고있는 mp3 파일들 ID3 태그 상테가 엉망이라서 한번 만들어 봤습니다.
쓸 일은 없겠지만 추후 github에 소스를 올리고 링크 하겠습니다.
깃허브 링크 : https://github.com/shinseungwon/SFileManager
2017년 5월 20일 토요일
VS 2015 heap corruption 에러
(1) new로 할당한 경우
char * a = new char[10]; 이라고 선언하고
a[10]이나 a[11]과 같이 원래 할당한 공간의 영역인 10보다 더 큰 영역에 접근하려고 하면 이와 같은 에러가 난다.
(2) malloc으로 할당한 경우
Test * test = (Test*)malloc(sizeof(Test*));
free(test);
이와 같이 메모리를 할당하고 해제했을 때 오류가 나는 경우이다.
실제로 위의 코드를 실행해보면 오류가 나지는 않지만
만약 malloc/free 부분에서 Heap 에러가 난다면 한번쯤 훑어봐야 하는 부분이다.
이 부분의 에러는 sizeof(Test)가 sizeof(Test*)보다 크기 때문에 일어나는 오류이다.
즉, 실제로 할당된 메모리의 크기는 sizeof(Test*)이지만
해제하려고 하는 메모리의 크기는 sizeof(Test)이기 때문에 Heap 에러가 나는 것이다.
그러므로 sizeof(Test*)를 sizeof(Test)로 바꾸면 해결 될 것이다.
2017년 5월 19일 금요일
비주얼 스튜디오 2013에서 "This function or variable may be unsafe" 에러
티스토리 뷰
드림스파크 (https://www.dreamspark.com) 에서 학생들에게는 비주얼 스튜디오 최신버전을 무료로 제공한다는걸 얼마 전에 알게 되어서 새로운 버전에 대한 기대감에 비주얼 스튜디오 2013 을 다운받아 사용하고 있었습니다.
근데 비주얼 스튜디오 2013에서는 컴파일러가 강화되었는지, 예전 2010버전에서는 Warning 정도로 처리했던 unsafe 함수들에 대해 에러로 처리하여 컴파일이 되지 않습니다.
예를 들면 scanf, strcpy 같은 함수들을 사용하면 아래와 같은 오류창을 띄우며 컴파일에 실패합니다.
"error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details."
scanf 는 안전하지 않으니, scanf_s를 사용하거나 _CRT_SECURE_NO_WARNINGS을 사용하라는 내용인데, 저 혼자 테스트 하는 프로젝트라서 _CRT_SECURE_NO_WARNINGS을 추가했습니다.
추가하는 방법은 [프로젝트] 메뉴에 제일 밑에 있는 메뉴를 보면 [(프로젝트명) 속성] 이라는 메뉴가 있습니다.
속성을 클릭한 다음에 아래와 같이 C/C++ 전처리기 탭에 들어갑니다.
뜨는 항목중, 전처리기 정의에 오른쪽에 보이는 화살표를 클릭하면 나타나는 <편집...> 을 눌러줍니다.
정의 내용안에
_CRT_SECURE_NO_WARNINGS
를 입력하고 확인 눌러줍니다.
전처리기 정의가 끝난 이후에는 scanf나 strcpy를 자유롭게 쓰셔도 에러처리 안하고 컴파일이 잘 됩니다.
위와 같은 방법도 있고, 소스코드의 제일 위에
하지만 소스코드 자체에 이런 "임시 에러 우회방법"을 사용하는것이 마음에 안들어 저는 프로젝트에 추가시키는 편입니다. 사실은 버퍼오버플로우 등의 프로그램 취약성때문에 사용하면 안 되는 함수이기 때문이죠. 하지말라는건 하지 않는게 좋은겁니다 :)
크리에이티브 커먼즈 라이선스
근데 비주얼 스튜디오 2013에서는 컴파일러가 강화되었는지, 예전 2010버전에서는 Warning 정도로 처리했던 unsafe 함수들에 대해 에러로 처리하여 컴파일이 되지 않습니다.
예를 들면 scanf, strcpy 같은 함수들을 사용하면 아래와 같은 오류창을 띄우며 컴파일에 실패합니다.
"error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details."
scanf 는 안전하지 않으니, scanf_s를 사용하거나 _CRT_SECURE_NO_WARNINGS을 사용하라는 내용인데, 저 혼자 테스트 하는 프로젝트라서 _CRT_SECURE_NO_WARNINGS을 추가했습니다.
추가하는 방법은 [프로젝트] 메뉴에 제일 밑에 있는 메뉴를 보면 [(프로젝트명) 속성] 이라는 메뉴가 있습니다.
속성을 클릭한 다음에 아래와 같이 C/C++ 전처리기 탭에 들어갑니다.
뜨는 항목중, 전처리기 정의에 오른쪽에 보이는 화살표를 클릭하면 나타나는 <편집...> 을 눌러줍니다.
정의 내용안에
_CRT_SECURE_NO_WARNINGS
를 입력하고 확인 눌러줍니다.
전처리기 정의가 끝난 이후에는 scanf나 strcpy를 자유롭게 쓰셔도 에러처리 안하고 컴파일이 잘 됩니다.
위와 같은 방법도 있고, 소스코드의 제일 위에
#define _CRT_SECURE_NO_WARNINGS을 선언해 주어도 됩니다. 제일 윗 줄에 선언하셔야합니다. (적어도 해당 함수를 담고 있는 헤더 윗줄에)
하지만 소스코드 자체에 이런 "임시 에러 우회방법"을 사용하는것이 마음에 안들어 저는 프로젝트에 추가시키는 편입니다. 사실은 버퍼오버플로우 등의 프로그램 취약성때문에 사용하면 안 되는 함수이기 때문이죠. 하지말라는건 하지 않는게 좋은겁니다 :)
크리에이티브 커먼즈 라이선스
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용하실 수 있습니다.
| 이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요. |
[MFC] 전역 변수 선언
MFC에서 전역변수를 생성하는 것은 간단하다.
다음은 배열의 전역변수 선언을 예로 생각해 본 것임.
먼저
stdafx.h 에서
extern int weight[100][50];
다음으로 stdafx.cpp 파일에 아래와 같이 선언해야 한다.
int weight[100][50];
main.cpp 등 필요한 곳에서 사용하면 된다.
음..여기서 삽질한 것은 stdafx.cpp 파일에도 반듯이 헤더에서 선언한 변수를 선언해야 한다는것!
다음은 배열의 전역변수 선언을 예로 생각해 본 것임.
먼저
stdafx.h 에서
extern int weight[100][50];
다음으로 stdafx.cpp 파일에 아래와 같이 선언해야 한다.
int weight[100][50];
main.cpp 등 필요한 곳에서 사용하면 된다.
음..여기서 삽질한 것은 stdafx.cpp 파일에도 반듯이 헤더에서 선언한 변수를 선언해야 한다는것!
| 이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요. |
C++ 파일명 바꾸기
TCHAR* pOldName = _T("Oldname_File.dat");
TCHAR* pNewName = _T("Renamed_File.dat");
try
{
CFile::Rename(pOldName, pNewName);
}
catch(CFileException* pEx )
{
TRACE(_T("File %20s not found, cause = %d\n"), pOldName,
pEx->m_cause);
pEx->Delete();
}
//C++ 파일명 바꾸기!
TCHAR ↔ char 변환
TCHAR ↔ char 변환
TCHAR -> char 변환
1
2
3
4
5
6
| TCHAR tmp[256]=L"한글입니당";int len = 256;char ctemp[256];WideCharToMultiByte(CP_ACP, 0, tmp, len, ctmp, len, NULL, NULL);printf("%s" , ctmp); |
char -> TCHAR 변환
1
2
3
| char charBuff[]="test";TCHAR szUniCode[256]={0,};MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, charBuff, strlen(charBuff), szUniCode, 256); |
| 이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요. |
2017년 5월 18일 목요일
ID3 파일 링크 시 주의사항
대부분 mp3파일은 id3v1 버전이므로
Mp3Tag.Link(Buffer, ID3TT_ID3V1); 위와같이 v1변수를 넣어줘야 됨.
그렇지 않을 경우 인식을 못하는 경우 발생.
Mp3Tag.Link(Buffer, ID3TT_ID3V1); 위와같이 v1변수를 넣어줘야 됨.
그렇지 않을 경우 인식을 못하는 경우 발생.
2017년 5월 17일 수요일
C++ id3lib 앨범아트 로드
//상단에 #include "MP3FileInfo.h" 추가
MP3FileInfo mp3fi;
ID3_Tag Mp3Tag;
// 해당 mp3 경로 char * 형이다.
Mp3Tag.Link(path);
const ID3_Frame * Mp3Frame;
Mp3Frame = Mp3Tag.Find(ID3FID_PICTURE);
if (Mp3Frame && Mp3Frame->Contains(ID3FN_DATA))
{
// 추출 이미지 thumb.bmp 로 저장 프로젝트 소스가 있는 곳에 저장된다.
Mp3Frame->Field(ID3FN_DATA).ToFile("thumb.bmp");
}
2017년 5월 16일 화요일
2017년 5월 15일 월요일
연산자
자료형
|
내용
|
char (%c)
|
8비트(1바이트) / 정수(문자)표현 . -128 ~ 127
|
short(%d)
|
16비트(2바이트) / 정수표현 / -32768 ~ 32726
|
int(%d)
|
32비트(4바이트) / 정수표현 / -2147483646 ~ 2147483647
|
long(%d)
|
int와 동일
|
long long(%d)
|
64비트(8바이트) / 정수표현 / -9223372036854775808 ~ 9223372036854775807
|
float(%lf)
|
32비트(4바이트) / 실수표현 / 10^-37 ~ 10^37
|
double(%lf)
|
64비트(8바이트) / 실수표현 / 1.7E-308 ~ 1.7E+308
|
long double(%lf)
|
64비트(8바이트) / 실수표현 / 3.4E-4932 ~ 3.4E+4932
|
문자열=%s/8진수=%o/16진수=%x
%.alf=소숫점a자리까지 출력
\n:줄바꿈 // \t:탭바꿈 // \r:현재 줄 첫 칸으로
\b:한칸 뒤로 // \a:경보음 출력
관계연산자
a>b : a가 b보다 큼
a<b : b가 a보다 큼
a>=b : a가 b보다 같거나 큼
a<=b : b가 a보다 같거나 큼
a==b : a와 b가 같음
a!=b :a와 b는 같지 않음
피연산자1 ? 피연산자2 : 피연산자3
- 피연산자 1이 참이면 피연산자 2를, 피연산자 1이 거짓이면 피연산자 3을 리턴
ex) (a>b)? a:b; //a가 더 크면 a를 리턴, 그렇지 않으면 b를 리턴
! : 값을 부정함 (0은 1로 1은 0으로)
ex)1에서 10까지 소수만 출력하는 프로그램
#include <stdio.h>
void main(){
int i,j;
int check=0;
for(i=2;i<=10;i++){
for(j=2;j<i;j++){
if(i%j==0) check=1; //소수가 아닐경우 check에 1 대입
}//각 수마다 각 수보다 작은 모든 양수로 나누어봄
if(!check) printf("%d\n",i); //if 안의 값이 1이 될경우 조건 실행 ->!check가 1이 될려면 check는 0이 되어야됨. 즉 나머지가 0이 되어선 안됨 = 소수임
check=0;//소수가 아니어서 check값이 1이 될 경우 다시 0으로 초기화
}
}
int i,j;
int check=0;
for(i=2;i<=10;i++){
for(j=2;j<i;j++){
if(i%j==0) check=1; //소수가 아닐경우 check에 1 대입
}//각 수마다 각 수보다 작은 모든 양수로 나누어봄
if(!check) printf("%d\n",i); //if 안의 값이 1이 될경우 조건 실행 ->!check가 1이 될려면 check는 0이 되어야됨. 즉 나머지가 0이 되어선 안됨 = 소수임
check=0;//소수가 아니어서 check값이 1이 될 경우 다시 0으로 초기화
}
}
증감연산자
i=5 일 때
++i * 3 = 18 이고
i++ * 3 = 15 임
a+=b : a=a+b
a-=b : a=a-b
a*=b : a=a*b
a/=b : a=a/b
주석/기타
//이 줄의 내용은 주석입니다.
/* 이 사이의 내용은 주석입니다.*/
입.출력함수
출력함수 -> printf("출력할 내용");
입력함수 -> scanf("%d", &a);//a의 형에 맞는 %d,%c,%lf,%s 등등을 사용.
형변환 연산자
연산 될 때만 형을 바꿔서 연산
(바뀔 자료형)변수
ex)
int a=3;
double b=6;
double(a)/b
C++ 형변환,정수 진법변환 모음
#include "stdafx.h"
#include "iostream"//C++ 콘솔 입출력
#include "stdlib.h"//동적할당
#include "math.h"//계산함수
#include "atlstr.h"//CString
#include "string"//string
using namespace std;
#pragma warning(disable:4996)
#pragma warning(disable:4244)
char* intConverter(char* number,int size, int K, int TARGET_K);
char* decTobi(int number);
char* decTohd(int number);
int _tmain(int argc, _TCHAR* argv[])
{
//itoa 사용법 (int to char[](2,10,16) 진법 )
int number=15;
char target[10];//반드시 정적배열로 선언(포인터 선언 X)
//char* target=(char*)malloc(sizeof(char)*10); //해도 됨.
cout <<"진법변환 + 정수형을 문자열로// 대상 숫자 : "<<number<<"(2,10,16)"<<endl;
cout <<itoa(number,target,2)<<endl;
cout <<itoa(number,target,10)<<endl;
cout <<itoa(number,target,16)<<endl;
cout <<endl;
//char[] to int
char number_2[]="147";
cout <<"char 형을 int 형으로, 대상 숫자 : "<<number_2<<endl;
cout << atoi(number_2)<<endl;
cout <<endl;
//char* to char[]
char* charpointer="char* to char[]";
char chararray[20];
cout <<"char* 형을 char[] 형으로, 대상 문자열 : "<<charpointer<<endl;
cout <<strcpy(chararray,charpointer)<<endl;
//CString to char*
char Buffer[255];
CString szString("CString to char");
size_t CharactersConverted = 0;
wcstombs_s(&CharactersConverted, Buffer, szString.GetLength()+1, szString, _TRUNCATE);
cout <<Buffer<<endl;
//char* to CString, CString cout 출력법
CString x1;
char* x2="char* to CString";
x1=(LPSTR)x2;
cout <<CStringA(x1).GetString()<<endl;//CString 을 cout 로 출력
//CString to int
CString cstringnumber("1442");
int x=_ttoi(cstringnumber);
cout <<x<<endl;
//int to CString, CString cout 출력법
int integernumber=142;
CString numberstring;
numberstring.Format(_T("%d"),integernumber);
cout <<CStringA(numberstring).GetString()<<endl;//CString 을 cout 로 출력
cout <<endl<<"진법변환"<<endl;
//진법변환(2,10,16)
char* binary_number="10110";
char* decimal_number="271";
char* hexadecimal_number="D7";
cout << intConverter(binary_number,5,2,10)<<endl;
cout << intConverter(binary_number,5,2,16)<<endl;
cout << intConverter(decimal_number,3,10,2)<<endl;
cout << intConverter(decimal_number,3,10,16)<<endl;
cout << intConverter(hexadecimal_number,2,16,2)<<endl;
cout << intConverter(hexadecimal_number,2,16,10)<<endl;
return 0;
}
//숫자를 문자열화 한 값, 그 문자열의 크기, 현재 진수, 바꿀 대상 진수
char* intConverter(char* number,int size, int K, int TARGET_K){
if((K!=2&&K!=10&&K!=16)||(TARGET_K!=2&&TARGET_K!=10&&TARGET_K!=16))
return NULL;
if(K==TARGET_K)
return number;
char *number_char=(char*)malloc(sizeof(char)*size);
for(int i=0;i<size;i++)
number_char[i]=number[i];
int decNumber=0;
if(K==2){
for(int i=0;i<size;i++){
if(number_char[i]!='0'&&number_char[i]!='1')
return NULL;
decNumber+=(int)(number_char[i]-'0')*pow((double)K,size-i-1);
}
}else if(K==16){
for(int i=0;i<size;i++){
int temp;
if((int)number_char[i]>47&&(int)number_char[i]<58)
temp=(int)number_char[i]-48;
else if((int)number_char[i]>64&&(int)number_char[i]<71)
temp=(int)number_char[i]-55;
else
return NULL;
decNumber+=temp*pow((double)K,size-i-1);
}
}else
decNumber = atoi(number_char);
if(TARGET_K==2)
return decTobi(decNumber);
else if(TARGET_K==10){
char* temp=(char*)malloc(size*sizeof(char));
itoa(decNumber,temp,10);
return temp;
}
else
return decTohd(decNumber);
}
// decimal -> binary
char* decTobi(int number){
int count =1;
int usenumber=number;
while(number>1){
number/=2;
count++;
}
char* msg=(char*)malloc(count*sizeof(char));
itoa(usenumber,msg,2);
return msg;
}
//decimal->hexadecimal
char* decTohd(int number){
int count =0;
int usenumber=number;
while(number>0){
number/=16;
count++;
}
char* msg=(char*)malloc(count*sizeof(char));
itoa(usenumber,msg,16);
return msg;
}
피드 구독하기:
글 (Atom)


