반응형


객체 초기화


새 오브젝트를 생성하면 내부의 속성 중 하나 이상에 값을 할당해야 합니다.

C# 3.0 이후에는 가독성 향상과 코드 단축을 위해 개체 자체의 초기화가 가능해졌습니다.


1
2
3
Customer c = new Customer();
c.Name = "James";
c.Address = "204 Lime Street";
cs


이와 같은 소스를 한 줄로 압축할 수 있습니다.


1
2
3
4
5
Customer c = new Customer
{
    Name="James",
    Address = "204 Lime Street"
};
cs




The using statement


자주 글꼴, 파일 핸들, 네트워크 리소스 등을 위해 시스템 자원을 사용합니다.



이런 리소스 등을 사용할 때 (Resource, You use it, dispose - 리소스, 할당 후 사용과 해제)란 중요한 점이 있지만, 메모리나 낭비되는 리소스들을 위한 Dispose 작업은 다들 잊어버립니다.

이런 리소스 등을 사용할 때 (Resource, You use it, dispose - 리소스, 할당 후 사용과 해제)란 중요한 점이 있지만, 메모리나 낭비되는 리소스들을 위한 Dispose 작업은 다들 잊어버립니다.


1
2
3
4
5
6
7
8
9
10
// 1. Allocation of the object
Font font1 = new Font("Arial"10.0f);
 
try{
    // 2. The bit where we use the resource
}finally{
    // 3. Disposal of the object
     if (font1 != null)
            ((IDisposable)font1).Dispose();
}
cs


그래서 Using 문을 사용해 코드를 축약합니다.


1
2
3
4
5
6
// Allocate the resource
using(Font font1 = new Font("Arial"10.0f))
{
      // The bit where we use the resource
}
      // Disposal is automatic
cs


using문은 실제 자원을 할당하고 관리하는 .NET 개체인데, "IDisposable" 인터페이스를 구현해 리소스 관리가 가능해 위와 같이 선언만 해놓으면 저절로 자원 관리가 됩니다.





Nullable objects


변수는 값을 가지고 있어야 하고, 비어있으면 안 됩니다.

때에 따라 비어야 할 때도 있고, 정의되지 않았을 경우 null을 할당하는 것이 편하기도 하며, .NET 2.0에서부터 Nullable을 도입했는데, 사용 예는 아래와 같습니다.


1
2
Nullable<int> x = null;
int? x = null;
cs


변수를 정의한 다음 ?를 넣고, 타입은 Nullable로 감싸서 사용합니다.



int? 자세한 설명 : http://www.csharpstudy.com/CSharp/CSharp-nullable.aspx



Automatic Properties


속성은 일반적으로 Getter과 Setter로 외부에 노출이 되고, 이를 이용해 값들을 할당합니다.


1
2
3
4
5
6
7
8
9
public class Person
{
    private string _firstName;
    public string FirstName;
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
}
cs


C# 3.0에서부터 자동 속성이 추가되어, 아래처럼 사용할 수 있습니다.


1
2
3
4
5
6
7
8
public class Person
{
    public string Firstname 
    {
        get;
        set;
    }
}
cs



C#의 컴파일러는 자동으로 백업되는 변수를 생성, 올바른 설정, 속성 설정 등을 수행하기 때문에, Public 클래스 대신에 String 변수를 생성할 수 있습니다.

C# 6 이상 버전에서는 필드와 유사하게 자동 구현 속성을 초기화할 수 있습니다.

C#
public string FirstName { get; set; } = "Jane";  


참고 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties






타입 유추


일반적으로 C#에선 아래와 같이 정의를 합니다.


1
string MyString = “Hello World”;
cs


=의 우측에 하나의 데이터 타입(string)을 적어 선언하는 건 너무나 일반적입니다.


근데, 이런 작업을 컴파일러가 대신할 순 없을까요?


1
var MyString = “Hello World”;
cs


바로 위의 코드 또한 "MyString"라는 문자열 변수를 생성합니다. 이런 일반적인 상황에서 유추(inference)를 통해 성능이 향상되진 않습니다.


컴파일 시, 어떤 작업 과정이든 데이터 타입에 대해선 먼저 생각하진 않습니다. 아래의 예를 통해 유추에 대해 알아볼 수 있습니다.


1
2
3
4
var SeniorStaff = Employees.Where(s => s.Age > 35);
 
foreach(var Member in SeniorStaff)
    Console.WriteLine("Name: {0} Age: {1}",Member.Name,Member.Age);
cs





람다 표현식(Lambda)


코드를 읽기에 난해할 수 있다는 단점이 있으나 내부적으로 구동하는 데 있어선 아주 좋은 방법입니다.


1
Func mySeniorStaffFilter = delegate(int a) { return a > 35; };
cs


위의 코드에선 직원의 수가 35보다 많다면 True를 반환합니다. 람다 표현 식으로는 좀 더 간결하고 (여기서는)읽기 쉽게 같은 의미를 표현할 수 있습니다.


1
Func mySeniorStaffFilter = a => a > 35;
cs


델리게이트를 이용하면 조금 더 코드를 멋지게 꾸밀 수도 있습니다.


1
var SeniorStaff = Employees.Where(s => s.Age > 35);
cs


string.IsNullOrEmpty


문자열이 비었는지 확인하려면 string.IsNullOrEmpty 함수를 사용해서 반환 값을 확인하세요.


1
2
3
4
if (String.IsNullOrEmpty(s) == true)
    return "is null or empty";
else
     return String.Format("(\"{0}\") is not null or empty", s);
cs


문자열의 대소문자 구분


때로는 Case(형식, 형태 등 변수의 속성)를 무시하는 문자열 비교 방법이 필요합니다. 일반적, 또는 전통적으로 문자열 비교 시 전체를 대문자나 소문자로 변환한 후 비교를 합니다.


1
str1.ToLower() == str2.ToLower()
cs


그렇지만 반복적으로 이를 이용하다 보면, 퍼포먼스 병목 현상이 벌어지기도 합니다. 대신에, String.Compare() 함수를 사용하면 프로그램의 수행 속도를 향상할 수 있습니다.


두 개의 문자열을 비교하면서 단순한 Case들은 무시하게 됩니다.


1
string.Compare(str1, str2, true== 0 //Ignoring cases
cs


0 이 반환된다면 두 문자열은 서로 같다는 뜻입니다.




ArrayList를 List<>로 교체하기


ArrayList는 여러 종류의 개체들을 다루기에 좋습니다.


그렇지만, ArrayList에 삽입되는 개체(변수)가 같은 타입이라면, 굳이 ArrayList를 고집할 필요 없이 List<>로 교체해서 성능을 향상할 필요가 있습니다.


1
2
3
4
ArrayList intList = new ArrayList();
intList.add(10);
 
return (int)intList[0+ 20;
cs


예를 들어, 이런 소스 코드를, 입력 목록의 변수 유형만 변경해 줍니다.


1
2
3
4
List<int> intList = new List<int>();
intList.add(10)
 
return intList[0+ 20;
cs


변수 타입을 별도로 캐스트 해줄 필요가 없어집니다. 성능 향상을 꾀할 수 있는 부분은 Integer와 같은 기본 데이터 타입들입니다.



+ ArrayList의 경우 Object 에 의한 참조를 사용하는 방식임으로 암시적 박싱이 일어나게 됨으로 성능상 느리다




&&와 || 사용하기


문장을 빌드할 땐 간단하게, &&, ||를 사용해 보세요(Visual Basic에서는 AndAlso, OrElse). 코드가 적어질 수 있고, 이 적은 코드는 향상된 성능뿐만 아니라 런타임 오류를 방지할 수도 있습니다.


아래는 간단한 예입니다.


1
if (object1 != null && object1.runMethod())
cs


object1은 NULL일 경우 object1.runMethod()가 실행되지 않습니다.


언제 StringBuilder를 사용해야 할까요?


StringBuilder 객체는 일반 문자열 함수보다 더 빠른 문자열 처리 속도를 보유하고 있습니다.

StringBuilder는 기다란 문자열을 처리하는데 아주 좋은 클래스이며, 문자열로 처리할 수 있는 부분을 StringBuilder로 대체하면 C# 소스 코드가 더 적은 리소스를 사용하고, 가독성도 높아질 수 있습니다.


문자열과 StringBuilder 객체를 효율적으로 사용함으로써 소스 코드를 최적화할 수 있습니다.


똑똑한 Try-Catch


Try-Catch문은 예를 들면, 웹이나 디바이스에 접근하는 예외를 프로그래머가 제어하기 위해서 사용이 됩니다.

하지만, Try-Catch문 때문에 소스 코드의 수행 시간은 늘어지니, 최대한 Try-Catch문의 코드는 단순하게 구성해야 합니다.


Replace Division


C#에선 Division의 Replace가 상대적으로 느립니다. 한 가지 방법으론 C#의 소스 코드를 최적화하기 위해 Multiplication-shift operation 부분을 다른 방식으로 대체하는 겁니다.



출처 1 - 10 C# Shorthands that improve productivity (링크 깨짐)

출처 2 - 7 Ways To Optimize C# Code



http://codingcoding.tistory.com/330 

반응형
반응형



문자열은 값이 텍스트인 String 형식의 개체입니다. 내부적으로 텍스트는 Char 개체의 순차적 읽기 전용 컬렉션으로 저장됩니다. C# 문자열의 끝에 null 종료 문자가 없으므로 C# 문자열에는 포함된 null 문자('\0')를 여러 개 사용할 수 있습니다. 문자열의 Length 속성은 유니코드 문자 수가 아닌 포함된 Char 개체 수를 나타냅니다. 문자열에서 개별 유니코드 코드 포인트에 액세스하려면 StringInfo 개체를 사용합니다.

문자열과 System.String

C#에서 string 키워드는 String의 별칭입니다. 따라서 String 및 string은 동일하며 원하는 명명 규칙을 사용할 수 있습니다. String 클래스는 문자열을 안전하게 작성, 조작 및 비교할 수 있도록 다양한 메서드를 제공합니다. 또한 C# 언어는 일반적인 문자열 작업을 간소화 하기 위해 일부 연산자를 오버로드합니다. 키워드에 대한 자세한 내용은 string을 참조하세요. 형식 및 메서드에 대한 자세한 내용은 String을 참조하세요.

문자열 선언 및 초기화

다음 예제에서와 같이 다양한 방법으로 문자열을 선언하고 초기화할 수 있습니다.

C#
// Declare without initializing.
string message1;

// Initialize to null.
string message2 = null;

// Initialize as an empty string.
// Use the Empty constant instead of the literal "".
string message3 = System.String.Empty;

//Initialize with a regular string literal.
string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0";

// Initialize with a verbatim string literal.
string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0";

// Use System.String if you prefer.
System.String greeting = "Hello World!";

// In local variables (i.e. within a method body)
// you can use implicit typing.
var temp = "I'm still a strongly-typed System.String!";

// Use a const string to prevent 'message4' from
// being used to store another string value.
const string message4 = "You can't get rid of me!";

// Use the String constructor only when creating
// a string from a char*, char[], or sbyte*. See
// System.String documentation for details.
char[] letters = { 'A', 'B', 'C' };
string alphabet = new string(letters);

문자 배열이 포함된 문자열을 초기화할 경우를 제외하고는 문자열 개체를 만들기 위해 new 연산자를 사용하지 않습니다.

문자열 길이가 0인 새 String 개체를 만들려면 Empty 상수 값이 포함된 문자열을 초기화하세요. 빈 문자열을 문자열 리터럴로 나타내면 ""로 표시됩니다. null 대신 Empty 값이 포함된 문자열을 초기화하면 NullReferenceException 발생을 줄일 수 있습니다. 액세스하기 전에 문자열의 값을 확인하려면 정적 IsNullOrEmpty(String) 메서드를 사용하세요.

문자열 개체의 불변성

문자열 개체는 변경할 수 없습니다. 즉, 생성된 후에는 바꿀 수 없습니다. 실제로 문자열을 수정하는 것으로 나타나는 모든 String 메서드 및 C# 연산자는 새로운 문자열 개체에 결과를 반환합니다. 다음 예제에서 s1  s2의 콘텐츠는 단일 문자열을 형성하도록 연결되며, 두 개의 원본 문자열은 변경되지 않습니다. += 연산자는 결합된 콘텐츠를 포함하는 새 문자열을 만듭니다. 새 개체는 s1 변수에 할당되며, 참조를 유지하는 변수가 없으므로 s1에 할당된 원래 개체는 가비지 수집을 위해 해제됩니다.

C#
string s1 = "A string is more ";
string s2 = "than the sum of its chars.";

// Concatenate s1 and s2. This actually creates a new
// string object and stores it in s1, releasing the
// reference to the original object.
s1 += s2;

System.Console.WriteLine(s1);
// Output: A string is more than the sum of its chars.

문자열 "수정"은 실제로 새 문자열을 만드는 것이므로 문자열에 대한 참조를 만들 때 주의해야 합니다. 문자열에 대한 참조를 만든 후 원래 문자열을 "수정"하더라도 참조는 문자열을 수정할 때 만든 새 개체가 아니라 원래 개체를 계속 가리킵니다. 이 동작은 다음 코드에서 볼 수 있습니다.

C#
string s1 = "Hello ";
string s2 = s1;
s1 += "World";

System.Console.WriteLine(s2);
//Output: Hello

원래 문자열에 대한 검색 및 바꾸기 작업과 같이, 수정을 기반으로 하는 새 문자열 작성 방법에 대한 자세한 내용은 방법: 문자열 콘텐츠 수정을 참조하세요.

일반 및 축자 문자열 리터럴

다음 예제와 같이 C#에서 제공하는 이스케이프 문자를 포함해야 하는 경우 일반 문자열 리터럴을 사용합니다.

C#
string columns = "Column 1\tColumn 2\tColumn 3";
//Output: Column 1        Column 2        Column 3

string rows = "Row 1\r\nRow 2\r\nRow 3";
/* Output:
  Row 1
  Row 2
  Row 3
*/

string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge";
//Output: "The Æolean Harp", by Samuel Taylor Coleridge

문자열 텍스트에 백슬래시 문자가 포함된 경우 가독성을 높이고 편의를 위해 축자 문자열을 사용합니다(예: 파일 경로). 축자 문자열에서는 문자열 텍스트의 일부로 줄 바꿈 문자가 유지되므로 여러 줄 문자열을 초기화하는 데 사용할 수 있습니다. 축자 문자열 내에 따옴표를 포함하려면 큰따옴표를 사용하세요. 다음 예제에서는 몇 가지 일반적인 축자 문자열에 대한 사용을 보여 줍니다.

C#
string filePath = @"C:\Users\scoleridge\Documents\";
//Output: C:\Users\scoleridge\Documents\

string text = @"My pensive SARA ! thy soft cheek reclined
    Thus on mine arm, most soothing sweet it is
    To sit beside our Cot,...";
/* Output:
My pensive SARA ! thy soft cheek reclined
   Thus on mine arm, most soothing sweet it is
   To sit beside our Cot,... 
*/

string quote = @"Her name was ""Sara.""";
//Output: Her name was "Sara."

문자열 이스케이프 시퀀스

이스케이프 시퀀스문자 이름유니코드 인코딩
\'작은따옴표0x0027
\"큰따옴표0x0022
\\백슬래시0x005C
\0Null0x0000
\a경고0x0007
\b백스페이스0x0008
\f폼 피드0x000C
\n줄 바꿈0x000A
\r캐리지 리턴0x000D
\t가로 탭0x0009
\U서로게이트 쌍의 경우 유니코드 이스케이프 시퀀스\Unnnnnnnn
\u유니코드 이스케이프 시퀀스\u0041 = "A"
\v세로 탭0x000B
\x길이가 변하는 경우를 제외하고 "\u"와 유사한 유니코드 이스케이프 시퀀스합니다.\x0041 = "A"
참고

컴파일 시 축자 문자열은 모두 동일한 이스케이프 시퀀스가 포함된 일반 문자열로 변환됩니다. 따라서 디버거 조사식 창에서 축자 문자열을 확인할 경우 소스 코드의 축자 버전이 아니라 컴파일러에 의해 추가된 이스케이프 문자가 나타납니다. 예를 들어 축자 문자열 @"C:\files.txt"는 조사식 창에 "c:\\files.txt"로 나타납니다.

형식 문자열

형식 문자열은 콘텐츠가 런타임 시 동적으로 결정될 수 있는 문자열입니다. 정적 Format 메서드를 사용하고, 런타임 시 다른 값으로 바뀔 자리 표시자를 중괄호에 포함하여 형식 문자열을 만들 수 있습니다. 다음 예제에서는 형식 문자열을 사용하여 루프의 각 반복의 결과를 출력합니다.

C#
class FormatString
{
    static void Main()
    {
        // Get user input.
        System.Console.WriteLine("Enter a number");
        string input = System.Console.ReadLine();

        // Convert the input string to an int.
        int j;
        System.Int32.TryParse(input, out j);

        // Write a different string each iteration.
        string s;
        for (int i = 0; i < 10; i++)
        {
            // A simple format string with no alignment formatting.
            s = System.String.Format("{0} times {1} = {2}", i, j, (i * j));
            System.Console.WriteLine(s);
        }

        //Keep the console window open in debug mode.
        System.Console.ReadKey();
    }
}

WriteLine 메서드를 한 번 오버로드하면 형식 문자열을 매개 변수로 가져옵니다. 따라서 메서드에 대한 명시적 호출이 없어도 형식 문자열 리터럴을 포함할 수 있습니다. 그러나 WriteLine은 형식 문자열이 아닌 문자열만 허용하므로, WriteLine 메서드를 사용하여 Visual Studio 출력 창에 디버그 출력을 표시할 경우에는 Format 메서드를 명시적으로 호출해야 합니다. 형식 문자열에 대한 자세한 내용은 형식 서식 지정을 참조하세요.

부분 문자열

부분 문자열은 문자열에 포함된 임의의 문자 시퀀스입니다. 원래 문자열 일부에서 새 문자열을 만들려면 Substring 메서드를 사용하세요. IndexOf 메서드를 사용하면 부분 문자열 항목을 하나 이상 검색할 수 있습니다. 지정된 부분 문자열의 모든 항목을 새 문자열로 바꾸려면 Replace 메서드를 사용하세요. Substring 메서드와 마찬가지로, Replace는 실제로 새 문자열을 반환하며, 원래 문자열은 수정되지 않습니다. 자세한 내용은 방법: 문자열 메서드를 사용하여 문자열 검색  방법: 문자열 콘텐츠 수정을 참조하세요.

C#
string s3 = "Visual C# Express";
System.Console.WriteLine(s3.Substring(7, 2));
// Output: "C#"

System.Console.WriteLine(s3.Replace("C#", "Basic"));
// Output: "Visual Basic Express"

// Index values are zero-based
int index = s3.IndexOf("C");
// index = 7

개별 문자 액세스

다음 예제와 같이 인덱스 값이 있는 배열 표기법을 사용하여 개별 문자에 대한 읽기 전용 액세스 권한을 얻을 수 있습니다.

C#
string s5 = "Printing backwards";

for (int i = 0; i < s5.Length; i++)
{
    System.Console.Write(s5[s5.Length - i - 1]);
}
// Output: "sdrawkcab gnitnirP"

문자열에서 개별 문자를 수정해야 하는 기능이 String 메서드에서 제공되지 않는 경우에는 StringBuilder 개체를 사용하여 개별 문자를 "현재 위치"에서 수정한 후 새 문자열을 만들어 StringBuilder 메서드로 결과를 저장할 수 있습니다. 다음 예제에서는 특정 방식으로 원래 문자열을 수정한 다음 나중에 사용할 수 있도록 결과를 저장해야 한다고 가정합니다.

C#
string question = "hOW DOES mICROSOFT wORD DEAL WITH THE cAPS lOCK KEY?";
System.Text.StringBuilder sb = new System.Text.StringBuilder(question);

for (int j = 0; j < sb.Length; j++)
{
    if (System.Char.IsLower(sb[j]) == true)
        sb[j] = System.Char.ToUpper(sb[j]);
    else if (System.Char.IsUpper(sb[j]) == true)
        sb[j] = System.Char.ToLower(sb[j]);
}
// Store the new string.
string corrected = sb.ToString();
System.Console.WriteLine(corrected);
// Output: How does Microsoft Word deal with the Caps Lock key?            

null 문자열 및 빈 문자열

빈 문자열은 문자가 포함되지 않은 System.String 개체의 인스턴스입니다. 빈 문자열은 빈 텍스트 필드를 나타내는 다양한 프로그래밍 시나리오에서 자주 사용됩니다. 빈 문자열은 유효한 System.String 개체이므로 빈 문자열에 대해 메서드를 호출할 수 있습니다. 빈 문자열은 다음과 같이 초기화됩니다.

string s = String.Empty;  

반면, null 문자열은 System.String 개체의 인스턴스를 참조하지 않으므로 null 문자열에서 메서드를 호출하려고 하면 NullReferenceException이 발생합니다. 그러나 다른 문자열과 연결 및 비교 작업에서는 null 문자열을 사용할 수 있습니다. 다음 예제에는 null 문자열에 대한 참조로 예외가 발생하거나 발생하지 않는 몇 가지 경우가 나와 있습니다.

C#
static void Main()
{
    string str = "hello";
    string nullStr = null;
    string emptyStr = String.Empty;

    string tempStr = str + nullStr;
    // Output of the following line: hello
    Console.WriteLine(tempStr);

    bool b = (emptyStr == nullStr);
    // Output of the following line: False
    Console.WriteLine(b);

    // The following line creates a new empty string.
    string newStr = emptyStr + nullStr;

    // Null strings and empty strings behave differently. The following
    // two lines display 0.
    Console.WriteLine(emptyStr.Length);
    Console.WriteLine(newStr.Length);
    // The following line raises a NullReferenceException.
    //Console.WriteLine(nullStr.Length);

    // The null character can be displayed and counted, like other chars.
    string s1 = "\x0" + "abc";
    string s2 = "abc" + "\x0";
    // Output of the following line: * abc*
    Console.WriteLine("*" + s1 + "*");
    // Output of the following line: *abc *
    Console.WriteLine("*" + s2 + "*");
    // Output of the following line: 4
    Console.WriteLine(s2.Length);
}

빠른 문자열 생성을 위한 StringBuilder 사용

.NET에서 문자열 작업은 고도로 최적화되어 있으므로 대부분의 경우 성능에 크게 영향을 주지 않습니다. 그러나 수백 번 또는 수천 번 실행하는 타이트 루프와 같은 일부 시나리오에서는 문자열 작업이 성능에 영향을 미칠 수 있습니다. 프로그램이 여러 문자열 조작을 수행하는 경우에는 StringBuilder 클래스에서 개선된 성능을 제공하는 문자열 버퍼를 만듭니다. StringBuilder 문자열을 사용하면 개별 문자를 다시 할당할 수도 있지만 기본 제공 문자열 데이터 형식을 지원하지는 않습니다. 예를 들어 이 코드는 새 문자열을 만들지 않고 문자열의 콘텐츠를 변경합니다.

C#
System.Text.StringBuilder sb = new System.Text.StringBuilder("Rat: the ideal pet");
sb[0] = 'C';
System.Console.WriteLine(sb.ToString());
System.Console.ReadLine();

//Outputs Cat: the ideal pet

이 예제에서 StringBuilder 개체는 숫자 형식 집합에서 문자열을 만드는 데 사용됩니다.

C#
class TestStringBuilder
{
    static void Main()
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        // Create a string composed of numbers 0 - 9
        for (int i = 0; i < 10; i++)
        {
            sb.Append(i.ToString());
        }
        System.Console.WriteLine(sb);  // displays 0123456789

        // Copy one character of the string (not possible with a System.String)
        sb[0] = sb[9];

        System.Console.WriteLine(sb);  // displays 9123456789
    }
}

문자열, 확장 메서드 및 LINQ

String 형식이 IEnumerable<T>을 구현하므로 문자열에서 Enumerable 클래스에 정의된 확장 메서드를 사용할 수 있습니다. 시각적인 혼란을 방지하기 위해 String 형식의 경우 이러한 메서드가 IntelliSense에서 제외되지만, 제외되더라도 사용할 수는 있습니다. 문자열에서 LINQ 쿼리 식을 사용할 수도 있습니다. 자세한 내용은 LINQ 및 문자열을 참조하세요.



https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/strings/


반응형
반응형




프로그램을 하다 보면 모든 것이 Collection 개념입니다.

배열은 당연히 그렇고 SQL 의 테이블, 탐색기, XML 등등..

 

.NET Framework에서 제공하는 기본 Collection 들의 제네릭 버전을 사용하기 위해서는

using System.Collections.Generic; 네임스페이스를 선언해야 합니다.

 

그럼 기본 Collection 중 제네릭 개념의 Collection을 봅시다. ( 같은 기능을 합니다. Generic 버젼이죠 )

    비 제네릭

 제네릭

 비고

 ArrayList

 List<T>

 동적 배열, 처음값:0, 일차원

 Hashtable

 Dictionary<K,V>

 Key와 Value를 쌍으로 저장하는 객체

 SortedList

 SortedList<K,V>

 Key를 기준으로 sorting 되어 관리하는 객체

 Stack

 Stack<T>

 선입후출 : 먼저 들어간 값이 나중에 나오는 객체 

 Queue

 Queue<T>

 선업선출 : 먼저 들어간 값이 먼저 나오는 객체

뭐 이것 말고 몇가지 더 있습니다. 비 제네릭과 제네릭에서 있는 것만..^^;;

인터페이스도 있고.. 뭐 기회가 되면 또 하기로 하고요.

 

이렇게 컬렉션(Collection) 들이 제네릭을 많이 사용합니다. ( 생각해 보면 그러겠죠. 데이터를 넣다 뺐다 해야 되니.. )

 

그럼 하나씩 봅시다. 예제는 제너릭 Collection만 구현 할것입니다. 비 제네릭의 경우는 뭐 특별히 기술은 안하려고요.

은근 캡처가 힘들기도 하고 2개 다 사용방법도 거의 같습니다.

 

1. ArrayList, List<T>

 

배열을 선언할때 미리 크기를 지정하여 사용하였으나 이 구조는 동적으로 배열을 구성할 수 있습니다. ( 편하겠군요 ^^ )

Add,Insert 메소드로 동적으로 데이터가 저장될 수 있습니다.

Remove,RemoveAll,RemoveAt 으로 데이터를 지울 수 있습니다.

배열이니 0 부터 시작합니다.

 

각 메소드에 대해 함 보시면 됩니다.

Remove 메소드는 같은 데이터가 2개이상이 있어도 앞의 한개만 지우는것을 볼수 있습니다.

Capacity 메소드의 경우는 배열의 크기를 볼수 있는데 배열 데이터의 갯수를 보여주는 count 하고는

개념이 틀린겁니다.

 

List 클래스가 동적배열을 할당한다고 했는데 내부에는 미리 배열의 크기를 지정해 놓고 있는겁니다.

배열 데이터의 갯수에 따라 말이죠. 생성시점에 크기는 0으로 지정됩니다 ( 메모리 효율적인듯 하네요 ㅎㅎ )

데이터가 들어오면 4로 지정되고

갯수가 4를 초과하면 크기가 8로, 그 이상이면 16,32 등으로 할당 됩니다.

 

여기선 데이터가 5이니 8로 나오는 군요. ( ArrayList는 초기 할당이 틀립니다. 16부터 입니다 )

 


결과입니다.

뭐 각 메소드들의 0,1 이렇게 잡는 것이 헷깔리시면 그때, 그때 마다 도움말 보시면 됩니다.

저도 뭐..ㅎㅎ

 

 

2. Hashtable,Dictionary<K,V>

 

Dictionary는 Hashtable의 제네릭 버젼입니다.

데이터가 key와 value 한쌍으로 저장되는 Collection 구조입니다.

 

key값은 유일해야 합니다. ( 유일성이 보장되어야 합니다. )

Key 값으로 찾으니 빠른 검색을 할 수 있습니다.

 

Key 와 Value 의 한쌍으로 구성된 Collection 이니 가져오는 방법이나 사용방법도 List 클래스는 차이가 있겠죠.

함 소스 코드를 보시기 바랍니다. ( 넘 말들이 무미건조해 지는듯.. 계속 반복되는 작업에..^^;; )

 

 

결과입니다.


 

 

3. SortedList, SortedList<K,V>

 

이름이 제네릭 버젼과 같습니다. 물론 두개의 네임스페이스는 틀립니다. 뭐 위의 Collection 들도 제너릭버젼과 당연 틀리겠죠.

 

SortedList<K,V>도 Dictionary<K,V> 처럼 Key 와 Value 가 한쌍으로 구성되어 있습니다.

Dictionary 와 사용 방법은 거의 동일합니다.

 

Dictionary 클래스에 Key 값 기준으로 정렬이 되는 것이 특징입니다. 알아서 정렬해 준다는 참 친절한..

 

뭐 기본 사용법만 나열하겠습니다. 다른 내용이 필요하면 도움말로..^^;;

 

예제는 Dictionary 와 SortedList 차이점을 보도록 하겠습니다. Key = 2 를 제일 나중에 추가 하고 배열된 순서대로 찍어 보도록 합니다.

그리고 SortedList는 List가 가지고 있던 동적배열 크기 할당 속성도 가지고 있네요. ( Capacity 항목이 있습니다. )

 


역시 이름에 걸맞게 젤 뒤어 추가해도 Key 값에 정렬되어 나오는 군요. 
Dictionary 는 추가한 순서대로 나오는걸 확인 할수 있습니다.


 

 

4. StackStack<T>

 

참 많이 들어본 키워드 입니다. 앞에 박싱 언방싱 할때 Value Type(값 타입) 개체들이 메모리에 사용되는 방식이죠.

한글로 "쌓다" 라는 단어입니다.

차근 차근 쌓아놓고 있으니 뺄때도 나중에 쌓은 것을 먼저 뺴야죠. 먼저 아래에 넣은 걸 뺴면 무너집니다.

LIFO(Last In First Out) 개념입니다.

 

자 또 봅시다. 계속 만드니 약간 귀찮아 질려는...쩝.. 그래도 몇개 안남았으니 열심히 해보겠습니다.

 

stack 은 Add/Remove 메소드가 아닌 Push/Pop으로 데이터를 넣고 빼고 합니다.

Pop() 메소드는 제일 위에 있는 데이터를 삭제하고

Peek() 메소드는 제일 위에 있는 데이터를 불러옵니다.

 

이러한 형태는 우리가 웹브라우져에서 앞으로 뒤로 가기 하면 최근 항목이 나오는데 그런 방식에 유용합니다.

 


역시 결과가 잘 나옵니다.

뭐 하나 하나 씩 살펴 보시면 됩니다.

 

스택 오버 플로워(StackOverFlow) 는 Stack 이 꽉 찼을때 발생합니다.

 

 

5. QueueQueue<T>

 

Queue는  Stack 과 상반되는 내용입니다. 먼저 들어간 것이 먼저 나오는 거죠FIFO(First In First Out) 라 표현 됩니다.

예를 들면 메일, 프린터 등과 같은 곳에서 사용 됩니다.

 

Queue는 Enqueue 로 값을 넣고 하나씩 Dequeue 로 값을 뺴 내면서 데이터를 없애는 식의 작업을 합니다. 

보시면 Enqueue / Dequeue 를 제외하곤 사용이 Stack 과 비슷하니 이해하기는 쉬울듯 하네요.

 


역시 잘 나오죠 ^^

그 외에 제네릭 버젼에만 있는 LinkedList<T>, ReadOnlyCollection<T>,KeyedCollection(K,V) 등은 추후에 다시 기술 하도록 하겟습니다.

 

Collection 에서 제네릭은 박싱/언박싱 에 따른 부하도 감소 할 수 있지만

미리 타입을 지정함으로써 잘못된 코드들에 대한 검증도 컴파일 단계에서 알 수 있게 해줍니다.

오류를 감소 시켜주는 거죠.

 

이번 시간엔 Collection 에 대한 예제만 보여드렸습니다. ( 개인적으론 약간 지루한.. ^^;; )

 

다음 시간엔 제너릭이 다른 형식으로 쓰이는 부분에 대해 말씀드리도록 하겠습니다.

 

수고 하십시요

 


반응형
반응형

제너릭 프로그래밍


장점은 하단에..



제네릭 메소드와 클래스 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System;
 
namespace GenericEx
{
    class ClassA
    {
        public static void CopyArray(int[] src, int[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
        
        public static void CopyArray(string[] src, string[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
        
        // 제네릭 메소드
        public static void GenericCopyArray<T>(T[] src, T[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
    }
    
    // 제네릭 클래스
    class GenericClassA<T>
    {
        public static void GenericCopyArray(T[] src, T[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
    }
 
    class MainClass
    {
        public static void Main (string[] args)
        {
                int[] iSrc = { 12345 };
                int[] iTarget = new int[5];
                
                string[] strSrc = { "ab""cd""ef""gh""ij" };
                string[] strTarget = new string[5];
                
                ClassA.CopyArray(iSrc, iTarget);
                foreach (int i in iTarget)
                    Console.WriteLine(i);
                
                ClassA.CopyArray(strSrc, strTarget);
                foreach (string s in strTarget)
                    Console.WriteLine(s);
                
                float[] fSrc = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f };
                float[] fTarget = new float[5];
                
                // 제네릭 메소드의 활용
                ClassA.GenericCopyArray<float>(fSrc, fTarget);
                foreach (float f in fTarget)
                    Console.WriteLine(f);
                
                // 제네릭 클래스의 활용
                GenericClassA<float>.GenericCopyArray(fSrc, fTarget);
                foreach (float f in fTarget)
                    Console.WriteLine(f);
                
                Console.ReadKey();
        }
    }
}
cs

LinkedList<T> 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System;
using System.Text;
using System.Collections.Generic;
 
namespace LinkedListTEx
{
    class MainClass
    {
        private static void Display(LinkedList<string> words, string test)
        {
            Console.WriteLine(test);
            foreach (string word in words)
            {
                Console.Write(word + " ");
            }
            Console.WriteLine();
            Console.WriteLine();
        }
        
        private static void IndicateNode(LinkedListNode<string> node, string test)
        {
            Console.WriteLine(test);
            if (node.List == null)
            {
                Console.WriteLine("Node '{0}' is not in the list.\n",
                                  node.Value);
                return;
            }
            
            StringBuilder result = new StringBuilder("(" + node.Value + ")");
            LinkedListNode<string> nodeP = node.Previous;
            
            while (nodeP != null)
            {
                result.Insert(0, nodeP.Value + " ");
                nodeP = nodeP.Previous;
            }
            
            node = node.Next;
            while (node != null)
            {
                result.Append(" " + node.Value);
                node = node.Next;
            }
            
            Console.WriteLine(result);
            Console.WriteLine();
        }
 
        public static void Main (string[] args)
        {
            string[] words = { "유니티""C#으로""스크립팅""한다"};
 
            // 연결 리스트의 생성
            LinkedList<string> sentence = new LinkedList<string>(words);
 
            Display(sentence, "연결 리스트의 값은:");
            Console.WriteLine("sentence.Contains(\"유니티\") = {0}", sentence.Contains("유니티"));
 
            sentence.AddFirst("오늘은");
            Display(sentence, "Test 1: 리스트 앞에 '오늘은' 문자열 추가");
 
            LinkedListNode<string> mark1 = sentence.First;
            sentence.RemoveFirst();
            sentence.AddLast(mark1);
            Display(sentence, "Test 2: 마지막 단어를 끝으로 이동");
 
            sentence.RemoveLast();
            sentence.AddLast("오늘만");
            Display(sentence, "Test 3: 마지막 단어를 '오늘만' 으로 변경");
 
            mark1 = sentence.Last;
            sentence.RemoveLast();
            sentence.AddFirst(mark1);
            Display(sentence, "Test 4: 마지막 노드를 첫 노드로 이동");
            
            sentence.RemoveFirst();
            LinkedListNode<string> current = sentence.FindLast("C#으로");
            IndicateNode(current, "Test 5: '스크립팅'이라는 단어를 찾아 가리킨다 ");
            
            sentence.AddAfter(current, "자바스크립트로");
            sentence.AddAfter(current, "그리고");
            IndicateNode(current, "Test 6: '스크립팅' 단어 뒤에 단어 추가");
 
            current = sentence.Find("유니티");
            IndicateNode(current, "Test 7: '유니티' 노드를 가리킨다");
 
            sentence.AddBefore(current, "오늘과");
            sentence.AddBefore(current, "내일은");
            IndicateNode(current, "Test 8: '오늘과', '내일은' 단어를 '유니티' 노드 앞에 추가");
        }
    }
}
cs

List<T> 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
 
namespace ListTEx
{    
    public class Enemy {
        public string Name { get; set; }        
        public int Level { get; set; }
        public int HP { get; set; }
        public int Exp { get; set; }
                
        public void printEnemyInfo() {
            Console.WriteLine ("Name : {0} Level : {1} HP : {2} Exp : {3}", Name, Level, HP, Exp);
        }
    }
 
    class MainClass
    {
        public static List<Enemy> enemyList;
 
        public static void Main (string[] args)
        {
            enemyList = new List<Enemy>();
            // 추가
            enemyList.Add (new Enemy () { Name = "Slime", Level = 1, HP = 200, Exp = 30 });
            enemyList.Add (new Enemy () { Name = "Zombie", Level = 2, HP = 100, Exp = 50 });
            enemyList.Add (new Enemy () { Name = "Skeleton", Level = 3, HP = 120, Exp = 80 });
            enemyList.Add (new Enemy () { Name = "Bugbear", Level = 4, HP = 300, Exp = 150 });
 
            // 삽입
            enemyList.Insert (2new Enemy () { Name = "Bugbear", Level = 5, HP = 350, Exp = 180 });
 
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyList) {
                enemy.printEnemyInfo();
            }
 
            // 삭제
            enemyList.RemoveAt (2);
 
            // 검색 후 삭제
            Enemy bugBear = enemyList.Find (x => x.Name.Equals ("Bugbear"));
            enemyList.Remove (bugBear);
 
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyList) {
                enemy.printEnemyInfo();
            }
        }
    }
}
cs

Dictionary<TKey, TValue> 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System;
using System.Collections.Generic;
 
namespace DictionaryTEx
{
    public class FileFormatTable {
        private Dictionary<stringstring> openWith;
        
        public FileFormatTable() {
            openWith = new Dictionary<stringstring>();
            
            // 추가
            openWith.Add("txt""notepad.exe");
            openWith.Add("bmp""paint.exe");
            openWith.Add("dib""paint.exe");
            openWith.Add("rtf""wordpad.exe");
            openWith.Add("odf""wordpad.exe");
            
            // 이미 할당 된 키일 경우 
            try
            {
                openWith.Add("txt""winword.exe");
            }
            catch
            {
                Console.WriteLine("An element with Key = \"txt\" already exists.");
            }
            
            // 제거
            openWith.Remove("odf");
        }
        
        public void printTable() {
            // 탐색
            foreach (KeyValuePair<stringstring> d in openWith)
                Console.WriteLine("Key = {0}, Value = {1}", d.Key, d.Value);
        }
    }
 
    class MainClass
    {
        public static void Main (string[] args)
        {
            FileFormatTable fileFormatTable = new FileFormatTable ();
            fileFormatTable.printTable ();
        }
    }
}
cs

Queue<T> 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
 
namespace QueueTEx
{
    public class Enemy {
        public string Name { get; set; }        
        public int Level { get; set; }
        public int HP { get; set; }
        public int Exp { get; set; }
        
        public void printEnemyInfo() {
            Console.WriteLine ("Name : {0} Level : {1} HP : {2} Exp : {3}", Name, Level, HP, Exp);
        }
    }
 
    class MainClass
    {
        public static Queue<Enemy> enemyQueue;
 
        public static void Main (string[] args)
        {
            enemyQueue = new Queue<Enemy>();
            // 추가
            enemyQueue.Enqueue (new Enemy () { Name = "Slime", Level = 1, HP = 200, Exp = 30 });
            enemyQueue.Enqueue (new Enemy () { Name = "Zombie", Level = 2, HP = 100, Exp = 50 });
            enemyQueue.Enqueue (new Enemy () { Name = "Skeleton", Level = 3, HP = 120, Exp = 80 });
            enemyQueue.Enqueue (new Enemy () { Name = "Bugbear", Level = 4, HP = 300, Exp = 150 });
            enemyQueue.Enqueue (new Enemy () { Name = "Bugbear", Level = 5, HP = 350, Exp = 180 });
            
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyQueue) {
                enemy.printEnemyInfo();
            }
            
            // 삭제
            Console.WriteLine ("********* Out *********");
            Enemy outEnemy = enemyQueue.Dequeue ();
            outEnemy.printEnemyInfo ();
 
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyQueue) {
                enemy.printEnemyInfo();
            }
 
            // 검색 후 삭제
            Console.WriteLine ("******** First *********");
            Enemy firstEnemy = enemyQueue.Peek();
            firstEnemy.printEnemyInfo ();
        }
    }
}
cs



Stack<T> 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
 
namespace StackTEx
{
    public class Enemy {
        public string Name { get; set; }        
        public int Level { get; set; }
        public int HP { get; set; }
        public int Exp { get; set; }
        
        public void printEnemyInfo() {
            Console.WriteLine ("Name : {0} Level : {1} HP : {2} Exp : {3}", Name, Level, HP, Exp);
        }
    }
 
    class MainClass
    {
        public static Stack<Enemy> enemyStack;
 
        public static void Main (string[] args)
        {
            enemyStack = new Stack<Enemy>();
            // 추가
            enemyStack.Push (new Enemy () { Name = "Slime", Level = 1, HP = 200, Exp = 30 });
            enemyStack.Push (new Enemy () { Name = "Zombie", Level = 2, HP = 100, Exp = 50 });
            enemyStack.Push (new Enemy () { Name = "Skeleton", Level = 3, HP = 120, Exp = 80 });
            enemyStack.Push (new Enemy () { Name = "Bugbear", Level = 4, HP = 300, Exp = 150 });
            enemyStack.Push (new Enemy () { Name = "Bugbear", Level = 5, HP = 350, Exp = 180 });
            
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyStack) {
                enemy.printEnemyInfo();
            }
            
            // 삭제
            Console.WriteLine ("********* Out *********");
            Enemy outEnemy = enemyStack.Pop ();
            outEnemy.printEnemyInfo ();
            
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyStack) {
                enemy.printEnemyInfo();
            }
            
            // 검색 후 삭제
            Console.WriteLine ("******** Last *********");
            Enemy lastEnemy = enemyStack.Peek();
            lastEnemy.printEnemyInfo ();
        }
    }
}
cs



출처: http://codepump.tistory.com/56 [CodePump.NET]








제네릭의 장점

 

제네릭을 사용하면 이전 버전의 공용 언어 런타임과 C# 언어에 적용되었던 제한 사항을 해결할 수 있습니다. 이전 버전에서는 유니버설 기본 형식인 Object와 형식 사이의 캐스팅을 통해 일반화를 수행했습니다. 제네릭 클래스를 만들면 컴파일 타임에 형식이 안전한 컬렉션을 만들 수 있습니다.

제네릭이 아닌 컬렉션 클래스를 사용하는 경우의 제한 사항을 보여 주는 예로는 .NET Framework 클래스 라이브러리에서 ArrayList 컬렉션 클래스를 사용하는 간단한 프로그램을 작성하는 경우를 들 수 있습니다. ArrayList는 참조나 값 형식을 저장하기 위해 수정하지 않고도 사용할 수 있는 매우 편리한 컬렉션 클래스입니다.

 

// The .NET Framework 1.1 way to create a list:
System.Collections.ArrayList list1 = new System.Collections.ArrayList();
list1.Add(3);
list1.Add(105);

System.Collections.ArrayList list2 = new System.Collections.ArrayList();
list2.Add("It is raining in Redmond.");
list2.Add("It is snowing in the mountains.");

 

그러나 이러한 편리함에는 상응하는 대가가 따릅니다. ArrayList에 추가되는 모든 참조나 값 형식은 Object에 암시적으로 업캐스팅됩니다. 항목이 값 형식이면 이를 목록에 추가할 때 boxing해야 하고 이를 검색할 때 unboxing해야 합니다. 캐스팅이나 boxing 및 unboxing 작업은 모두 성능을 저하시킵니다. 큰 컬렉션을 반복해야 하는 시나리오에서는 boxing과 unboxing의 영향을 결코 무시할 수 없습니다.

다른 제한 사항으로는 컴파일 타임에 형식을 검사할 수 없다는 점을 들 수 있습니다. ArrayList는 Object에 모든 항목을 캐스팅하므로 컴파일 타임에 클라이언트 코드가 다음과 같은 작업을 수행하지 못하도록 막을 수 없습니다.

 

System.Collections.ArrayList list = new System.Collections.ArrayList();
// Add an integer to the list.
list.Add(3);
// Add a string to the list. This will compile, but may cause an error later.
list.Add("It is raining in Redmond.");

int t = 0;
// This causes an InvalidCastException to be returned.
foreach (int x in list)
{
    t += x;
}

유형이 다른 컬렉션을 만드는 경우 규칙을 정확히 따르는 의도적인 선택일지라도 문자열과 ints를 단일 ArrayList에 결합하면 프로그래밍 오류가 발생할 확률이 더 커지고 이러한 오류는 런타임 이전에 발견할 수 없습니다.

버전 1.0 및 1.1의 C# 언어에서는 고유한 형식별 컬렉션을 작성하는 방법으로만 .NET Framework 기본 클래스 라이브러리 컬렉션 클래스에서 코드를 일반화하는 위험을 방지할 수 있었습니다. 물론 이러한 클래스는 여러 데이터 형식에 다시 사용할 수 없으므로 일반화의 이점이 사라지고 저장하려는 각 형식에 대해 클래스를 다시 작성해야만 합니다.

ArrayList 및 기타 유사한 클래스에 실제로 필요한 것은 클라이언트 코드에서 사용하려는 특정 데이터 형식을 인스턴스별로 지정할 수 있는 방법입니다. 이렇게 하면 T:System.Object로 업캐스팅할 필요가 없어지고 컴파일러에서 형식을 검사할 수도 있게 됩니다. 즉, ArrayList에는 형식 매개 변수가 필요합니다. 제네릭은 바로 이러한 요구 사항을 충족시킵니다. N:System.Collections.Generic 네임스페이스의 제네릭 List<(Of <(T>)>) 컬렉션에서는 컬렉션에 항목을 추가하는 동일한 작업을 다음과 같이 수행할 수 있습니다.

 

// The .NET Framework 2.0 way to create a list
List<int> list1 = new List<int>();

// No boxing, no casting:
list1.Add(3);

// Compile-time error:
// list1.Add("It is raining in Redmond.");




반응형

'프로그래밍(Programming) > C#' 카테고리의 다른 글

String 문자열(C# 프로그래밍 가이드)  (0) 2017.09.18
제네릭 Collection(컬렉션) 개체  (0) 2017.09.08
using 과 Dispose()  (0) 2017.07.19
확장메서드 public static class  (0) 2017.07.18
프로퍼티 value  (0) 2015.11.17
반응형

C# Using 문 

블락  벗어나면 자동 Dispose()되고 예외 상황에서도 Dispose 처리가 된다

근대 번역이 뭔가 되게 이상한데..;




출처 :  https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/using-statement

예제

다음 예제에서는 using 문을 사용하는 방법을 보여 줍니다.

C#
using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

주의

File  Font는 관리되지 않는 리소스에 액세스하는 관리되는 형식의 예입니다(이 경우 파일 핸들 및 장치 컨텍스트). 다른 많은 종류의 관리되지 않는 리소스 및 이를 캡슐화하는 클래스 라이브러리 형식이 있습니다. 그러한 모든 형식은 IDisposable 인터페이스를 구현해야 합니다.



일반적으로 IDisposable 개체를 사용할 경우 using 문에서 선언 및 인스턴스화해야 합니다. using 문은 올바른 방법으로 개체에서 Dispose 메서드를 호출하며, (앞서 설명한 대로 사용하는 경우) Dispose가 호출되자마자 개체 자체가 범위를 벗어나도록 만듭니다. using 블록 내에서 개체는 읽기 전용이며 수정하거나 다시 할당할 수 없습니다.


using 문을 사용하면 개체에서 메서드를 호출하는 동안 예외가 발생하더라도 Dispose가 호출됩니다. try 블록 내부에 개체를 배치하고 finally 블록에서 Dispose를 호출해도 동일한 결과를 얻을 수 있습니다. 실제로 컴파일러는 이 방법으로 using 문을 변환합니다. 이전의 코드 예제는 컴파일 시 다음 코드로 확장됩니다(개체의 제한된 범위를 만드는 여분의 중괄호 참고).

C#
{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}






여러분, using 키워드에 대해 아시나요?
보통 Namespace 를 Import 할때 쓰이죠.

using System.IO; public static class F { public bool Exist(string path) { return File.Exist(path); } }

이런식으로요! 네이버 코드 컴포먼트가 언어를 잘 인식 못하는거 같은데 기분 탓이려나..

하지만, 제가 알아낸 using 기능은 네임스페이스의 Import 외에도 2가지 용도가 더 있습니다!

먼저, 첫번째!
IDispose 인터페이스에게 상속 받은 클래스들을 사용할 때 쓰입니다.
설명을 뭐라 해야할지 모르겠군요.
IDispose 인터페이스를 상속한 클래스들은 Dispose() 메서드가 있는데요. using 을 사용하면 using 문 밖으로 나가는 순간 그 클래스를 자동으로 Dispose() 처리 해 줍니다. 예시를 볼까요?

using (BinaryReader sr = new BinaryReader(new FileStream(File.Open(@".\test.txt"))) { MessageBox.Show(sr.ReadString()); }

진짜로 언어 인식을 잘 못하는거 같은데.
이런식으로요! 자동으로 Dispose 를 해주니 메모리 관리하기에 더 효율적이죠..! 제가 찾은 마지막 하나!
클래스(class) 나 구조체(struct), 인터페이스(interface), 열거자(enum)를 줄여서 사용하고자 할때 도 사용 됩니다.
이것 역시 제가 설명을 잘 못하겠네요. 일단 예시를 보시죠!
이건 네임스페이스 Import 하듯이 사용하시면 됩니다.

using Environ = System.Environment;

언어를 인식 못하는게 맞는거 같다.
이런식으로요! 이렇게 해 두시면

System.Environment.StartupPath

이런식으로 호출 해야 하는것을

Environ.StartupPath

이렇게 호출할 수 있습니다..!
다른 예시도 하나 보여 드리죠.

using Dis = System.IDispose; public class Test : Dis // 원래는 System.IDispose 이렇게 했어야 했으나 using 을 사용해서 줄였으므로 Dis 로 사용 가능. { public void Dispose() { base.Dispose(); } }

이런식으로요..!

그럼 전 이만 물러 나겠습니다.
좋은 정보 되셨으면 좋겠네요!


반응형
반응형

확장 메서드를 사용하기 위해서 클래스를 만드는데 이때 클래스명이 문법적의 컴파일 오류에 있어서 중요한것은 아니고 


public static void method(타입 src, ... ){
}


의 함수에서 타입 자리에 어떤 타입이 오는지에 따라 호출 할 수있는 원본 클래스가 결정된다는 부분이 구분역할로써 중요하다





\



C# 확장 메서드 (Extension Method) 

C# 3.0부터 지원하는 확장메서드(Extension Method)는 특수한 종류의 static 메서드로서 마치 다른 클래스의 인스턴스 메서드인 것처럼 사용된다. 일반적으로 instance 메서드를 추가하기 위해서는 해당 클래스안에 메서드를 추가한다. 만약 여러 개의 클래스들에 instance 메서드를 추가하고 싶다면, 각 클래스마다 메서드를 추가해 주어야 한다 (물론 Base Class가 있는 경우, 클래스 상속을 이용할 수도 있다). 

확장 메서드는 메서드가 사용될 클래스명(혹은 Type)을 첫번째 파라미터로 지정하여 마치 해당 클래스(혹은 Type)가 확장메서드를 인스턴스 메서드로 갖는 것과 같은 효과를 낸다. 약간 특이한 문법이지만, 확장 메서드의 첫번째 파라미터는 앞에 항상 this를 써준다.

아래 예제는 String 클래스를 첫번째 파라미터로 갖는 확장메서드 즉 String 클래스에서만 동작하는 확장 메서드를 정의한 예이다. 

using System;
using System.Text;

namespace MySystem
{
   // static class를 정의
   public static class ExClass
   {
      // static 확장메서드를 정의. 첫번째 파라미터는
      // 어떤 클래스가 사용할 지만 지정. 
      public static string ToChangeCase(this String str)
      {
         StringBuilder sb = new StringBuilder();
         foreach (var ch in str)
         {
            if (ch >= 'A' && ch <= 'Z')
               sb.Append((char)('a' + ch - 'A'));
            else if (ch >= 'a' && ch <= 'x')
               sb.Append((char)('A' + ch - 'a'));
            else
               sb.Append(ch);
         }
         return sb.ToString();
      }

      // 이 확장메서드는 파라미터 ch가 필요함
      public static bool Found(this String str, char ch)
      {
         int position = str.IndexOf(ch);
         return position >= 0;
      }
   }

   class Program
   {
      static void Main(string[] args)
      {
         string s = "This is a Test";
         
         // s객체 즉 String객체가
         // 확장메서드의 첫 파리미터임
         // 실제 ToChangeCase() 메서드는
         // 파라미터를 갖지 않는다.
         string s2 = s.ToChangeCase();

         // String 객체가 사용하는 확장메서드이며
         // z 값을 파라미터로 사용
         bool found = s.Found('z');
      }
   }
}


http://www.csharpstudy.com/CSharp/CSharp-extension-method.aspx




다른 예제



public bool Contains(String value);


해당 문자열에 value 값이 포함되있는지 비교한다. 


해당 키워드는 대소문자를 구문한다.


 


만약 대소문자를 비교하려면 StringExtensions 기능을 이용하여 만들어줘야한다.

(C#은 Extensions를 이용하여 객체 내부의 명시된 클래스를 사용하여 기능을 확장을 정의할 수 있다. )





이렇게 대소문자 구분 무시

 



반응형

'프로그래밍(Programming) > C#' 카테고리의 다른 글

제너릭의 장점과 boxing & unboxing  (0) 2017.09.08
using 과 Dispose()  (0) 2017.07.19
프로퍼티 value  (0) 2015.11.17
정적 생성자가 호출되는 시점  (0) 2015.11.14
AssemblyInfo.cs  (0) 2015.11.11
반응형

what code is it?


#define FORCENOINLINE __attribute__((noinline)) /* Force code to NOT be inline */



In brief, this code not use inline in c++ code and UE4 use it as FORCENOINLINE  macro,



FORCENOINLINE construct()  , you know what it means?, that's right





How can I tell gcc not to inline a function?



Say I have this small function in a source file

static void foo() {}

and I build an optimized version of my binary yet I don't want this function inlined (for optimization purposes). is there a macro I can add in a source code to prevent the inlining?

shareimprove this question
   
Thanks for this question! I was profiling with oprofile when a function did not show up, the answers here fixed this. – Simon A. Eugster Oct 29 '11 at 9:17

You want the gcc-specific noinline attribute.

This function attribute prevents a function from being considered for inlining. If the function does not have side-effects, there are optimizations other than inlining that causes function calls to be optimized away, although the function call is live. To keep such calls from being optimized away, put asm ("");

Use it like this:

void __attribute__ ((noinline)) foo() 
{
  ...
}
shareimprove this answer
25 
Using gcc 4.4.3 on Arch Linux, I get a syntax error with the attribute placed as above. It works correctly when it precedes the function (e.g., attribute ((noinline)) void foo() {}) – mrkj Apr 16 '10 at 14:24
2 
Arduino also wanted it placed before the function. – Peter N Lewis Feb 24 '12 at 9:49
2 
Edited to fix the attribute syntax. – Quuxplusone Jun 21 '13 at 20:59
   
The asm("") construct is actually fairly cross-platform and got the job done. I did it for x86 Linux and it did not cause a build problem on PowerPC AIX. Thanks for this useful suggestion! – Marty Nov 6 '14 at 23:58
   
Using gcc 6.2.1 on Arch Linux, no problem. – ManuelSchneid3r Oct 1 '16 at 14:46 






반응형
반응형


CPU 와 FPU 는  서로 다른 CPU 인데 현재에 들어서는 CPU 안에FPU가 탑재 되어 있는 방식이다


즉 CPU 안에 레지스터공간(EAX, EDX, 등등...)이 따로 존재 하듯이 FPU 안에도 FPU 만의 레지스터가 따로 존재한다(ST0~ST7 , c0, c2, c3 등등....)



CPU에서 점프를 할때 JZ 등으로 바로 점프 할 수 있으나 FPU 는 float 를 계산하기 위한 전용 처리 장치이기 때문에


float 연산은 FPU 에서 처리 하고 이에 대한 비교 연산이 FPU 내의 C0 , C2, C3  플래그에 기록 되게 되는데 이것을


CPU 의 상태 플래그로 넘겨 줘야 CPU에서 점프처리가 가능하게 된다



과정


1. fcmp 로 float 값을 비교

2. fstsw ax  로 fpu 상태 레지스터 값을 ax로 복사한다

3. sahf 로 ah 를 상태 레지스터로 (EFLAGS(SF:ZF:0:AF:0:PF:1:CF) = AH;)

4. 점프(점프는 unsigned 와 패리티 비트 관련된 걸로 할 수 있는데 c0, c2, c3 값이 세팅 되는 것이 부모 있는 수치에 관련된 플레그로 세팅되지 않기 때문)

          : FPU 는 캐리처리 없이 연산 됨으로



SAHFLoad SF, ZF, AF, PF, and CF from AH into EFLAGS register.



이미지로 간략히 나타내면 다음 처럼 그릴 수 있다






축약 과정


원래는 위 처럼 동작 하지만 이를 간소화ㅎ여 실행 할 수 있는 명령어 FCOMI 가 있다

1. fcmp 로 float 값을 비교

2. FCOMI ST(0), ST(1)       이 명령어가 FPU 레지스터 플래그 들을 CPU 상태 레지스터플래그로 옮겨주는 작업도 처리해준다, 펜티업 프로 이상에서 작동

4. 점프(점프는 unsigned 와 패리티 비트 관련된 걸로 할 수 있는데 c0, c2, c3 값이 세팅 되는 것이 부모 있는 수치에 관련된 플레그로 세팅되지 않기 때문)

          : FPU 는 캐리처리 없이 연산 됨으로




반응형
반응형



x86 Instruction Set Reference

Derived from the September 2014 version of the Intel® 64 and IA-32 Architectures Software Developer’s Manual, volumes 2A and 2B.

More info at zneak/x86doc

This reference is not perfect. It's been mechanically separated into distinct files by a dumb script. It may be enough to replace the official documentation on your weekend reverse engineering project, but in doubt, go get the official and freely available documentation.

Download documentation set

AAAASCII Adjust After Addition
AADASCII Adjust AX Before Division
AAMASCII Adjust AX After Multiply
AASASCII Adjust AL After Subtraction
ADCAdd with Carry
ADCXUnsigned Integer Addition of Two Operands with Carry Flag
ADDAdd
ADDPDAdd Packed Double-Precision Floating-Point Values
ADDPSAdd Packed Single-Precision Floating-Point Values
ADDSDAdd Scalar Double-Precision Floating-Point Values
ADDSSAdd Scalar Single-Precision Floating-Point Values
ADDSUBPDPacked Double-FP Add/Subtract
ADDSUBPSPacked Single-FP Add/Subtract
ADOXUnsigned Integer Addition of Two Operands with Overflow Flag
AESDECPerform One Round of an AES Decryption Flow
AESDECLASTPerform Last Round of an AES Decryption Flow
AESENCPerform One Round of an AES Encryption Flow
AESENCLASTPerform Last Round of an AES Encryption Flow
AESIMCPerform the AES InvMixColumn Transformation
AESKEYGENASSISTAES Round Key Generation Assist
ANDLogical AND
ANDNLogical AND NOT
ANDNPDBitwise Logical AND NOT of Packed Double-Precision Floating-Point Values
ANDNPSBitwise Logical AND NOT of Packed Single-Precision Floating-Point Values
ANDPDBitwise Logical AND of Packed Double-Precision Floating-Point Values
ANDPSBitwise Logical AND of Packed Single-Precision Floating-Point Values
ARPLAdjust RPL Field of Segment Selector
BEXTRBit Field Extract
BLENDPDBlend Packed Double Precision Floating-Point Values
BLENDPSBlend Packed Single Precision Floating-Point Values
BLENDVPDVariable Blend Packed Double Precision Floating-Point Values
BLENDVPSVariable Blend Packed Single Precision Floating-Point Values
BLSIExtract Lowest Set Isolated Bit
BLSMSKGet Mask Up to Lowest Set Bit
BLSRReset Lowest Set Bit
BOUNDCheck Array Index Against Bounds
BSFBit Scan Forward
BSRBit Scan Reverse
BSWAPByte Swap
BTBit Test
BTCBit Test and Complement
BTRBit Test and Reset
BTSBit Test and Set
BZHIZero High Bits Starting with Specified Bit Position
CALLCall Procedure
CBWConvert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword
CDQConvert Word to Doubleword/Convert Doubleword to Quadword
CDQEConvert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword
CLACClear AC Flag in EFLAGS Register
CLCClear Carry Flag
CLDClear Direction Flag
CLFLUSHFlush Cache Line
CLIClear Interrupt Flag
CLTSClear Task-Switched Flag in CR0
CMCComplement Carry Flag
CMOVccConditional Move
CMPCompare Two Operands
CMPPDCompare Packed Double-Precision Floating-Point Values
CMPPSCompare Packed Single-Precision Floating-Point Values
CMPSCompare String Operands
CMPSBCompare String Operands
CMPSDCompare String Operands
CMPSDCompare Scalar Double-Precision Floating-Point Values
CMPSQCompare String Operands
CMPSSCompare Scalar Single-Precision Floating-Point Values
CMPSWCompare String Operands
CMPXCHGCompare and Exchange
CMPXCHG16BCompare and Exchange Bytes
CMPXCHG8BCompare and Exchange Bytes
COMISDCompare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
COMISSCompare Scalar Ordered Single-Precision Floating-Point Values and Set EFLAGS
CPUIDCPU Identification
CQOConvert Word to Doubleword/Convert Doubleword to Quadword
CRC32Accumulate CRC32 Value
CVTDQ2PDConvert Packed Dword Integers to Packed Double-Precision FP Values
CVTDQ2PSConvert Packed Dword Integers to Packed Single-Precision FP Values
CVTPD2DQConvert Packed Double-Precision FP Values to Packed Dword Integers
CVTPD2PIConvert Packed Double-Precision FP Values to Packed Dword Integers
CVTPD2PSConvert Packed Double-Precision FP Values to Packed Single-Precision FP Values
CVTPI2PDConvert Packed Dword Integers to Packed Double-Precision FP Values
CVTPI2PSConvert Packed Dword Integers to Packed Single-Precision FP Values
CVTPS2DQConvert Packed Single-Precision FP Values to Packed Dword Integers
CVTPS2PDConvert Packed Single-Precision FP Values to Packed Double-Precision FP Values
CVTPS2PIConvert Packed Single-Precision FP Values to Packed Dword Integers
CVTSD2SIConvert Scalar Double-Precision FP Value to Integer
CVTSD2SSConvert Scalar Double-Precision FP Value to Scalar Single-Precision FP Value
CVTSI2SDConvert Dword Integer to Scalar Double-Precision FP Value
CVTSI2SSConvert Dword Integer to Scalar Single-Precision FP Value
CVTSS2SDConvert Scalar Single-Precision FP Value to Scalar Double-Precision FP Value
CVTSS2SIConvert Scalar Single-Precision FP Value to Dword Integer
CVTTPD2DQConvert with Truncation Packed Double-Precision FP Values to Packed Dword Integers
CVTTPD2PIConvert with Truncation Packed Double-Precision FP Values to Packed Dword Integers
CVTTPS2DQConvert with Truncation Packed Single-Precision FP Values to Packed Dword Integers
CVTTPS2PIConvert with Truncation Packed Single-Precision FP Values to Packed Dword Integers
CVTTSD2SIConvert with Truncation Scalar Double-Precision FP Value to Signed Integer
CVTTSS2SIConvert with Truncation Scalar Single-Precision FP Value to Dword Integer
CWDConvert Word to Doubleword/Convert Doubleword to Quadword
CWDEConvert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword
DAADecimal Adjust AL after Addition
DASDecimal Adjust AL after Subtraction
DECDecrement by 1
DIVUnsigned Divide
DIVPDDivide Packed Double-Precision Floating-Point Values
DIVPSDivide Packed Single-Precision Floating-Point Values
DIVSDDivide Scalar Double-Precision Floating-Point Values
DIVSSDivide Scalar Single-Precision Floating-Point Values
DPPDDot Product of Packed Double Precision Floating-Point Values
DPPSDot Product of Packed Single Precision Floating-Point Values
EMMSEmpty MMX Technology State
ENTERMake Stack Frame for Procedure Parameters
EXTRACTPSExtract Packed Single Precision Floating-Point Value
F2XM1Compute 2x–1
FABSAbsolute Value
FADDAdd
FADDPAdd
FBLDLoad Binary Coded Decimal
FBSTPStore BCD Integer and Pop
FCHSChange Sign
FCLEXClear Exceptions
FCMOVccFloating-Point Conditional Move
FCOMCompare Floating Point Values
FCOMICompare Floating Point Values and Set EFLAGS
FCOMIPCompare Floating Point Values and Set EFLAGS
FCOMPCompare Floating Point Values
FCOMPPCompare Floating Point Values
FCOSCosine
FDECSTPDecrement Stack-Top Pointer
FDIVDivide
FDIVPDivide
FDIVRReverse Divide
FDIVRPReverse Divide
FFREEFree Floating-Point Register
FIADDAdd
FICOMCompare Integer
FICOMPCompare Integer
FIDIVDivide
FIDIVRReverse Divide
FILDLoad Integer
FIMULMultiply
FINCSTPIncrement Stack-Top Pointer
FINITInitialize Floating-Point Unit
FISTStore Integer
FISTPStore Integer
FISTTPStore Integer with Truncation
FISUBSubtract
FISUBRReverse Subtract
FLDLoad Floating Point Value
FLD1Load Constant
FLDCWLoad x87 FPU Control Word
FLDENVLoad x87 FPU Environment
FLDL2ELoad Constant
FLDL2TLoad Constant
FLDLG2Load Constant
FLDLN2Load Constant
FLDPILoad Constant
FLDZLoad Constant
FMULMultiply
FMULPMultiply
FNCLEXClear Exceptions
FNINITInitialize Floating-Point Unit
FNOPNo Operation
FNSAVEStore x87 FPU State
FNSTCWStore x87 FPU Control Word
FNSTENVStore x87 FPU Environment
FNSTSWStore x87 FPU Status Word
FPATANPartial Arctangent
FPREMPartial Remainder
FPREM1Partial Remainder
FPTANPartial Tangent
FRNDINTRound to Integer
FRSTORRestore x87 FPU State
FSAVEStore x87 FPU State
FSCALEScale
FSINSine
FSINCOSSine and Cosine
FSQRTSquare Root
FSTStore Floating Point Value
FSTCWStore x87 FPU Control Word
FSTENVStore x87 FPU Environment
FSTPStore Floating Point Value
FSTSWStore x87 FPU Status Word
FSUBSubtract
FSUBPSubtract
FSUBRReverse Subtract
FSUBRPReverse Subtract
FTSTTEST
FUCOMUnordered Compare Floating Point Values
FUCOMICompare Floating Point Values and Set EFLAGS
FUCOMIPCompare Floating Point Values and Set EFLAGS
FUCOMPUnordered Compare Floating Point Values
FUCOMPPUnordered Compare Floating Point Values
FWAITWait
FXAMExamine ModR/M
FXCHExchange Register Contents
FXRSTORRestore x87 FPU, MMX, XMM, and MXCSR State
FXSAVESave x87 FPU, MMX Technology, and SSE State
FXTRACTExtract Exponent and Significand
FYL2XCompute y ∗ log2x
FYL2XP1Compute y ∗ log2(x +1)
HADDPDPacked Double-FP Horizontal Add
HADDPSPacked Single-FP Horizontal Add
HLTHalt
HSUBPDPacked Double-FP Horizontal Subtract
HSUBPSPacked Single-FP Horizontal Subtract
IDIVSigned Divide
IMULSigned Multiply
INInput from Port
INCIncrement by 1
INSInput from Port to String
INSBInput from Port to String
INSDInput from Port to String
INSERTPSInsert Packed Single Precision Floating-Point Value
INSWInput from Port to String
INT 3Call to Interrupt Procedure
INT nCall to Interrupt Procedure
INTOCall to Interrupt Procedure
INVDInvalidate Internal Caches
INVLPGInvalidate TLB Entries
INVPCIDInvalidate Process-Context Identifier
IRETInterrupt Return
IRETDInterrupt Return
JMPJump
JccJump if Condition Is Met
LAHFLoad Status Flags into AH Register
LARLoad Access Rights Byte
LDDQULoad Unaligned Integer 128 Bits
LDMXCSRLoad MXCSR Register
LDSLoad Far Pointer
LEALoad Effective Address
LEAVEHigh Level Procedure Exit
LESLoad Far Pointer
LFENCELoad Fence
LFSLoad Far Pointer
LGDTLoad Global/Interrupt Descriptor Table Register
LGSLoad Far Pointer
LIDTLoad Global/Interrupt Descriptor Table Register
LLDTLoad Local Descriptor Table Register
LMSWLoad Machine Status Word
LOCKAssert LOCK# Signal Prefix
LODSLoad String
LODSBLoad String
LODSDLoad String
LODSQLoad String
LODSWLoad String
LOOPLoop According to ECX Counter
LOOPccLoop According to ECX Counter
LSLLoad Segment Limit
LSSLoad Far Pointer
LTRLoad Task Register
LZCNTCount the Number of Leading Zero Bits
MASKMOVDQUStore Selected Bytes of Double Quadword
MASKMOVQStore Selected Bytes of Quadword
MAXPDReturn Maximum Packed Double-Precision Floating-Point Values
MAXPSReturn Maximum Packed Single-Precision Floating-Point Values
MAXSDReturn Maximum Scalar Double-Precision Floating-Point Value
MAXSSReturn Maximum Scalar Single-Precision Floating-Point Value
MFENCEMemory Fence
MINPDReturn Minimum Packed Double-Precision Floating-Point Values
MINPSReturn Minimum Packed Single-Precision Floating-Point Values
MINSDReturn Minimum Scalar Double-Precision Floating-Point Value
MINSSReturn Minimum Scalar Single-Precision Floating-Point Value
MONITORSet Up Monitor Address
MOVMove
MOVMove to/from Control Registers
MOVMove to/from Debug Registers
MOVAPDMove Aligned Packed Double-Precision Floating-Point Values
MOVAPSMove Aligned Packed Single-Precision Floating-Point Values
MOVBEMove Data After Swapping Bytes
MOVDMove Doubleword/Move Quadword
MOVDDUPMove One Double-FP and Duplicate
MOVDQ2QMove Quadword from XMM to MMX Technology Register
MOVDQAMove Aligned Double Quadword
MOVDQUMove Unaligned Double Quadword
MOVHLPSMove Packed Single-Precision Floating-Point Values High to Low
MOVHPDMove High Packed Double-Precision Floating-Point Value
MOVHPSMove High Packed Single-Precision Floating-Point Values
MOVLHPSMove Packed Single-Precision Floating-Point Values Low to High
MOVLPDMove Low Packed Double-Precision Floating-Point Value
MOVLPSMove Low Packed Single-Precision Floating-Point Values
MOVMSKPDExtract Packed Double-Precision Floating-Point Sign Mask
MOVMSKPSExtract Packed Single-Precision Floating-Point Sign Mask
MOVNTDQStore Double Quadword Using Non-Temporal Hint
MOVNTDQALoad Double Quadword Non-Temporal Aligned Hint
MOVNTIStore Doubleword Using Non-Temporal Hint
MOVNTPDStore Packed Double-Precision Floating-Point Values Using Non-Temporal Hint
MOVNTPSStore Packed Single-Precision Floating-Point Values Using Non-Temporal Hint
MOVNTQStore of Quadword Using Non-Temporal Hint
MOVQMove Doubleword/Move Quadword
MOVQMove Quadword
MOVQ2DQMove Quadword from MMX Technology to XMM Register
MOVSMove Data from String to String
MOVSBMove Data from String to String
MOVSDMove Data from String to String
MOVSDMove Scalar Double-Precision Floating-Point Value
MOVSHDUPMove Packed Single-FP High and Duplicate
MOVSLDUPMove Packed Single-FP Low and Duplicate
MOVSQMove Data from String to String
MOVSSMove Scalar Single-Precision Floating-Point Values
MOVSWMove Data from String to String
MOVSXMove with Sign-Extension
MOVSXDMove with Sign-Extension
MOVUPDMove Unaligned Packed Double-Precision Floating-Point Values
MOVUPSMove Unaligned Packed Single-Precision Floating-Point Values
MOVZXMove with Zero-Extend
MPSADBWCompute Multiple Packed Sums of Absolute Difference
MULUnsigned Multiply
MULPDMultiply Packed Double-Precision Floating-Point Values
MULPSMultiply Packed Single-Precision Floating-Point Values
MULSDMultiply Scalar Double-Precision Floating-Point Values
MULSSMultiply Scalar Single-Precision Floating-Point Values
MWAITMonitor Wait
MULXUnsigned Multiply Without Affecting Flags
MWAITMonitor Wait
NEGTwo's Complement Negation
NOPNo Operation
NOTOne's Complement Negation
ORLogical Inclusive OR
ORPDBitwise Logical OR of Double-Precision Floating-Point Values
ORPSBitwise Logical OR of Single-Precision Floating-Point Values
OUTOutput to Port
OUTSOutput String to Port
OUTSBOutput String to Port
OUTSDOutput String to Port
OUTSWOutput String to Port
PABSBPacked Absolute Value
PABSDPacked Absolute Value
PABSWPacked Absolute Value
PACKSSDWPack with Signed Saturation
PACKSSWBPack with Signed Saturation
PACKUSDWPack with Unsigned Saturation
PACKUSWBPack with Unsigned Saturation
PADDBAdd Packed Integers
PADDDAdd Packed Integers
PADDQAdd Packed Quadword Integers
PADDSBAdd Packed Signed Integers with Signed Saturation
PADDSWAdd Packed Signed Integers with Signed Saturation
PADDUSBAdd Packed Unsigned Integers with Unsigned Saturation
PADDUSWAdd Packed Unsigned Integers with Unsigned Saturation
PADDWAdd Packed Integers
PALIGNRPacked Align Right
PANDLogical AND
PANDNLogical AND NOT
PAUSESpin Loop Hint
PAVGBAverage Packed Integers
PAVGWAverage Packed Integers
PBLENDVBVariable Blend Packed Bytes
PBLENDWBlend Packed Words
PCLMULQDQCarry-Less Multiplication Quadword
PCMPEQBCompare Packed Data for Equal
PCMPEQDCompare Packed Data for Equal
PCMPEQQCompare Packed Qword Data for Equal
PCMPEQWCompare Packed Data for Equal
PCMPESTRIPacked Compare Explicit Length Strings, Return Index
PCMPESTRMPacked Compare Explicit Length Strings, Return Mask
PCMPGTBCompare Packed Signed Integers for Greater Than
PCMPGTDCompare Packed Signed Integers for Greater Than
PCMPGTQCompare Packed Data for Greater Than
PCMPGTWCompare Packed Signed Integers for Greater Than
PCMPISTRIPacked Compare Implicit Length Strings, Return Index
PCMPISTRMPacked Compare Implicit Length Strings, Return Mask
PDEPParallel Bits Deposit
PEXTParallel Bits Extract
PEXTRBExtract Byte/Dword/Qword
PEXTRDExtract Byte/Dword/Qword
PEXTRQExtract Byte/Dword/Qword
PEXTRWExtract Word
PHADDDPacked Horizontal Add
PHADDSWPacked Horizontal Add and Saturate
PHADDWPacked Horizontal Add
PHMINPOSUWPacked Horizontal Word Minimum
PHSUBDPacked Horizontal Subtract
PHSUBSWPacked Horizontal Subtract and Saturate
PHSUBWPacked Horizontal Subtract
PINSRBInsert Byte/Dword/Qword
PINSRDInsert Byte/Dword/Qword
PINSRQInsert Byte/Dword/Qword
PINSRWInsert Word
PMADDUBSWMultiply and Add Packed Signed and Unsigned Bytes
PMADDWDMultiply and Add Packed Integers
PMAXSBMaximum of Packed Signed Byte Integers
PMAXSDMaximum of Packed Signed Dword Integers
PMAXSWMaximum of Packed Signed Word Integers
PMAXUBMaximum of Packed Unsigned Byte Integers
PMAXUDMaximum of Packed Unsigned Dword Integers
PMAXUWMaximum of Packed Word Integers
PMINSBMinimum of Packed Signed Byte Integers
PMINSDMinimum of Packed Dword Integers
PMINSWMinimum of Packed Signed Word Integers
PMINUBMinimum of Packed Unsigned Byte Integers
PMINUDMinimum of Packed Dword Integers
PMINUWMinimum of Packed Word Integers
PMOVMSKBMove Byte Mask
PMOVSXPacked Move with Sign Extend
PMOVZXPacked Move with Zero Extend
PMULDQMultiply Packed Signed Dword Integers
PMULHRSWPacked Multiply High with Round and Scale
PMULHUWMultiply Packed Unsigned Integers and Store High Result
PMULHWMultiply Packed Signed Integers and Store High Result
PMULLDMultiply Packed Signed Dword Integers and Store Low Result
PMULLWMultiply Packed Signed Integers and Store Low Result
PMULUDQMultiply Packed Unsigned Doubleword Integers
POPPop a Value from the Stack
POPAPop All General-Purpose Registers
POPADPop All General-Purpose Registers
POPCNTReturn the Count of Number of Bits Set to 1
POPFPop Stack into EFLAGS Register
POPFDPop Stack into EFLAGS Register
POPFQPop Stack into EFLAGS Register
PORBitwise Logical OR
PREFETCHWPrefetch Data into Caches in Anticipation of a Write
PREFETCHWT1Prefetch Vector Data Into Caches with Intent to Write and T1 Hint
PREFETCHhPrefetch Data Into Caches
PSADBWCompute Sum of Absolute Differences
PSHUFBPacked Shuffle Bytes
PSHUFDShuffle Packed Doublewords
PSHUFHWShuffle Packed High Words
PSHUFLWShuffle Packed Low Words
PSHUFWShuffle Packed Words
PSIGNBPacked SIGN
PSIGNDPacked SIGN
PSIGNWPacked SIGN
PSLLDShift Packed Data Left Logical
PSLLDQShift Double Quadword Left Logical
PSLLQShift Packed Data Left Logical
PSLLWShift Packed Data Left Logical
PSRADShift Packed Data Right Arithmetic
PSRAWShift Packed Data Right Arithmetic
PSRLDShift Packed Data Right Logical
PSRLDQShift Double Quadword Right Logical
PSRLQShift Packed Data Right Logical
PSRLWShift Packed Data Right Logical
PSUBBSubtract Packed Integers
PSUBDSubtract Packed Integers
PSUBQSubtract Packed Quadword Integers
PSUBSBSubtract Packed Signed Integers with Signed Saturation
PSUBSWSubtract Packed Signed Integers with Signed Saturation
PSUBUSBSubtract Packed Unsigned Integers with Unsigned Saturation
PSUBUSWSubtract Packed Unsigned Integers with Unsigned Saturation
PSUBWSubtract Packed Integers
PTESTLogical Compare
PUNPCKHBWUnpack High Data
PUNPCKHDQUnpack High Data
PUNPCKHQDQUnpack High Data
PUNPCKHWDUnpack High Data
PUNPCKLBWUnpack Low Data
PUNPCKLDQUnpack Low Data
PUNPCKLQDQUnpack Low Data
PUNPCKLWDUnpack Low Data
PUSHPush Word, Doubleword or Quadword Onto the Stack
PUSHAPush All General-Purpose Registers
PUSHADPush All General-Purpose Registers
PUSHFPush EFLAGS Register onto the Stack
PUSHFDPush EFLAGS Register onto the Stack
PXORLogical Exclusive OR
RCL—Rotate
RCPPSCompute Reciprocals of Packed Single-Precision Floating-Point Values
RCPSSCompute Reciprocal of Scalar Single-Precision Floating-Point Values
RCR—Rotate
RDFSBASERead FS/GS Segment Base
RDGSBASERead FS/GS Segment Base
RDMSRRead from Model Specific Register
RDPMCRead Performance-Monitoring Counters
RDRANDRead Random Number
RDSEEDRead Random SEED
RDTSCRead Time-Stamp Counter
RDTSCPRead Time-Stamp Counter and Processor ID
REPRepeat String Operation Prefix
REPERepeat String Operation Prefix
REPNERepeat String Operation Prefix
REPNZRepeat String Operation Prefix
REPZRepeat String Operation Prefix
RETReturn from Procedure
ROL—Rotate
ROR—Rotate
RORXRotate Right Logical Without Affecting Flags
ROUNDPDRound Packed Double Precision Floating-Point Values
ROUNDPSRound Packed Single Precision Floating-Point Values
ROUNDSDRound Scalar Double Precision Floating-Point Values
ROUNDSSRound Scalar Single Precision Floating-Point Values
RSMResume from System Management Mode
RSQRTPSCompute Reciprocals of Square Roots of Packed Single-Precision Floating-Point Values
RSQRTSSCompute Reciprocal of Square Root of Scalar Single-Precision Floating-Point Value
SAHFStore AH into Flags
SALShift
SARShift
SARXShift Without Affecting Flags
SBBInteger Subtraction with Borrow
SCASScan String
SCASBScan String
SCASDScan String
SCASWScan String
SETccSet Byte on Condition
SFENCEStore Fence
SGDTStore Global Descriptor Table Register
SHLShift
SHLDDouble Precision Shift Left
SHLXShift Without Affecting Flags
SHRShift
SHRDDouble Precision Shift Right
SHRXShift Without Affecting Flags
SHUFPDShuffle Packed Double-Precision Floating-Point Values
SHUFPSShuffle Packed Single-Precision Floating-Point Values
SIDTStore Interrupt Descriptor Table Register
SLDTStore Local Descriptor Table Register
SMSWStore Machine Status Word
SQRTPDCompute Square Roots of Packed Double-Precision Floating-Point Values
SQRTPSCompute Square Roots of Packed Single-Precision Floating-Point Values
SQRTSDCompute Square Root of Scalar Double-Precision Floating-Point Value
SQRTSSCompute Square Root of Scalar Single-Precision Floating-Point Value
STACSet AC Flag in EFLAGS Register
STCSet Carry Flag
STDSet Direction Flag
STISet Interrupt Flag
STMXCSRStore MXCSR Register State
STOSStore String
STOSBStore String
STOSDStore String
STOSQStore String
STOSWStore String
STRStore Task Register
SUBSubtract
SUBPDSubtract Packed Double-Precision Floating-Point Values
SUBPSSubtract Packed Single-Precision Floating-Point Values
SUBSDSubtract Scalar Double-Precision Floating-Point Values
SUBSSSubtract Scalar Single-Precision Floating-Point Values
SWAPGSSwap GS Base Register
SYSCALLFast System Call
SYSENTERFast System Call
SYSEXITFast Return from Fast System Call
SYSRETReturn From Fast System Call
TESTLogical Compare
TZCNTCount the Number of Trailing Zero Bits
UCOMISDUnordered Compare Scalar Double-Precision Floating-Point Values and Set EFLAGS
UCOMISSUnordered Compare Scalar Single-Precision Floating-Point Values and Set EFLAGS
UD2Undefined Instruction
UNPCKHPDUnpack and Interleave High Packed Double-Precision Floating-Point Values
UNPCKHPSUnpack and Interleave High Packed Single-Precision Floating-Point Values
UNPCKLPDUnpack and Interleave Low Packed Double-Precision Floating-Point Values
UNPCKLPSUnpack and Interleave Low Packed Single-Precision Floating-Point Values
VBROADCASTBroadcast Floating-Point Data
VCVTPH2PSConvert 16-bit FP Values to Single-Precision FP Values
VCVTPS2PHConvert Single-Precision FP value to 16-bit FP value
VERRVerify a Segment for Reading or Writing
VERWVerify a Segment for Reading or Writing
VEXTRACTF128Extract Packed Floating-Point Values
VEXTRACTI128Extract packed Integer Values
VFMADD132PDFused Multiply-Add of Packed Double-Precision Floating-Point Values
VFMADD132PSFused Multiply-Add of Packed Single-Precision Floating-Point Values
VFMADD132SDFused Multiply-Add of Scalar Double-Precision Floating-Point Values
VFMADD132SSFused Multiply-Add of Scalar Single-Precision Floating-Point Values
VFMADD213PDFused Multiply-Add of Packed Double-Precision Floating-Point Values
VFMADD213PSFused Multiply-Add of Packed Single-Precision Floating-Point Values
VFMADD213SDFused Multiply-Add of Scalar Double-Precision Floating-Point Values
VFMADD213SSFused Multiply-Add of Scalar Single-Precision Floating-Point Values
VFMADD231PDFused Multiply-Add of Packed Double-Precision Floating-Point Values
VFMADD231PSFused Multiply-Add of Packed Single-Precision Floating-Point Values
VFMADD231SDFused Multiply-Add of Scalar Double-Precision Floating-Point Values
VFMADD231SSFused Multiply-Add of Scalar Single-Precision Floating-Point Values
VFMADDSUB132PDFused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values
VFMADDSUB132PSFused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values
VFMADDSUB213PDFused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values
VFMADDSUB213PSFused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values
VFMADDSUB231PDFused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values
VFMADDSUB231PSFused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values
VFMSUB132PDFused Multiply-Subtract of Packed Double-Precision Floating-Point Values
VFMSUB132PSFused Multiply-Subtract of Packed Single-Precision Floating-Point Values
VFMSUB132SDFused Multiply-Subtract of Scalar Double-Precision Floating-Point Values
VFMSUB132SSFused Multiply-Subtract of Scalar Single-Precision Floating-Point Values
VFMSUB213PDFused Multiply-Subtract of Packed Double-Precision Floating-Point Values
VFMSUB213PSFused Multiply-Subtract of Packed Single-Precision Floating-Point Values
VFMSUB213SDFused Multiply-Subtract of Scalar Double-Precision Floating-Point Values
VFMSUB213SSFused Multiply-Subtract of Scalar Single-Precision Floating-Point Values
VFMSUB231PDFused Multiply-Subtract of Packed Double-Precision Floating-Point Values
VFMSUB231PSFused Multiply-Subtract of Packed Single-Precision Floating-Point Values
VFMSUB231SDFused Multiply-Subtract of Scalar Double-Precision Floating-Point Values
VFMSUB231SSFused Multiply-Subtract of Scalar Single-Precision Floating-Point Values
VFMSUBADD132PDFused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values
VFMSUBADD132PSFused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values
VFMSUBADD213PDFused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values
VFMSUBADD213PSFused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values
VFMSUBADD231PDFused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values
VFMSUBADD231PSFused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values
VFNMADD132PDFused Negative Multiply-Add of Packed Double-Precision Floating-Point Values
VFNMADD132PSFused Negative Multiply-Add of Packed Single-Precision Floating-Point Values
VFNMADD132SDFused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values
VFNMADD132SSFused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values
VFNMADD213PDFused Negative Multiply-Add of Packed Double-Precision Floating-Point Values
VFNMADD213PSFused Negative Multiply-Add of Packed Single-Precision Floating-Point Values
VFNMADD213SDFused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values
VFNMADD213SSFused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values
VFNMADD231PDFused Negative Multiply-Add of Packed Double-Precision Floating-Point Values
VFNMADD231PSFused Negative Multiply-Add of Packed Single-Precision Floating-Point Values
VFNMADD231SDFused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values
VFNMADD231SSFused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values
VFNMSUB132PDFused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values
VFNMSUB132PSFused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values
VFNMSUB132SDFused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values
VFNMSUB132SSFused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values
VFNMSUB213PDFused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values
VFNMSUB213PSFused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values
VFNMSUB213SDFused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values
VFNMSUB213SSFused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values
VFNMSUB231PDFused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values
VFNMSUB231PSFused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values
VFNMSUB231SDFused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values
VFNMSUB231SSFused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values
VGATHERDPDGather Packed DP FP Values Using Signed Dword/Qword Indices
VGATHERDPSGather Packed SP FP values Using Signed Dword/Qword Indices
VGATHERQPDGather Packed DP FP Values Using Signed Dword/Qword Indices
VGATHERQPSGather Packed SP FP values Using Signed Dword/Qword Indices
VINSERTF128Insert Packed Floating-Point Values
VINSERTI128Insert Packed Integer Values
VMASKMOVConditional SIMD Packed Loads and Stores
VPBLENDDBlend Packed Dwords
VPBROADCASTBroadcast Integer Data
VPERM2F128Permute Floating-Point Values
VPERM2I128Permute Integer Values
VPERMDFull Doublewords Element Permutation
VPERMILPDPermute Double-Precision Floating-Point Values
VPERMILPSPermute Single-Precision Floating-Point Values
VPERMPDPermute Double-Precision Floating-Point Elements
VPERMPSPermute Single-Precision Floating-Point Elements
VPERMQQwords Element Permutation
VPGATHERDDGather Packed Dword Values Using Signed Dword/Qword Indices
VPGATHERDQGather Packed Qword Values Using Signed Dword/Qword Indices
VPGATHERQDGather Packed Dword Values Using Signed Dword/Qword Indices
VPGATHERQQGather Packed Qword Values Using Signed Dword/Qword Indices
VPMASKMOVConditional SIMD Integer Packed Loads and Stores
VPSLLVDVariable Bit Shift Left Logical
VPSLLVQVariable Bit Shift Left Logical
VPSRAVDVariable Bit Shift Right Arithmetic
VPSRLVDVariable Bit Shift Right Logical
VPSRLVQVariable Bit Shift Right Logical
VTESTPDPacked Bit Test
VTESTPSPacked Bit Test
VZEROALLZero All YMM Registers
VZEROUPPERZero Upper Bits of YMM Registers
WAITWait
WBINVDWrite Back and Invalidate Cache
WRFSBASEWrite FS/GS Segment Base
WRGSBASEWrite FS/GS Segment Base
WRMSRWrite to Model Specific Register
XABORTTransactional Abort
XACQUIREHardware Lock Elision Prefix Hints
XADDExchange and Add
XBEGINTransactional Begin
XCHGExchange Register/Memory with Register
XENDTransactional End
XGETBVGet Value of Extended Control Register
XLATTable Look-up Translation
XLATBTable Look-up Translation
XORLogical Exclusive OR
XORPDBitwise Logical XOR for Double-Precision Floating-Point Values
XORPSBitwise Logical XOR for Single-Precision Floating-Point Values
XRELEASEHardware Lock Elision Prefix Hints
XRSTORRestore Processor Extended States
XRSTORSRestore Processor Extended States Supervisor
XSAVESave Processor Extended States
XSAVECSave Processor Extended States with Compaction
XSAVEOPTSave Processor Extended States Optimized
XSAVESSave Processor Extended States Supervisor
XSETBVSet Extended Control Register
XTESTTest If In Transactional Execution




http://www.felixcloutier.com/x86/





반응형
반응형
ENTER numbytes, nestinglevel

numbytes 는 변수로 사용하고자 하는 바이트 수치
nestinglevel 은 { 를 중첩해서 써 내려갈 때의 중첩 수치


Enter명령은 nestingLevel 이 0 일때 아래처럼 매칭이 되는데


일반적 방법

ENTER 명령어 사용

push ebp

mov ebp,esp

sub esp,4

enter 4,0


nestingLevel 에 수치가 주어 지게 되면 이전 , 이전전... ebp 들을 저장하여 이전에 사용했던 변수들에 접근 하도록허용해준다

enter 로 들어 가서 할당한다음 leave 로 할당한 메모리를 해제 하는 처리를 해야함


if 먼저 아래처럼 asm 코드를 작성 한다고 했을 때


_asm {


enter 4, 0 0)

enter 4, 1 1)


enter 4, 2 2)


enter 4, 3 3)


enter 4, 4 4)


enter 4, 5 5)


}




먼저 아래처럼 asm 코드를 작성 한다고 했을 때 아래 처럼 실제 메모리 주소에 이전 ebp 값들이 어떻게 쌓이는지 확인 할 수가 있으며 이 값들로 한 함수 내에서 아래와 같은 괄호로 묶은 지역 변수들을 참조 할 수 있는 형태를 구성 할 수 있다


void stackFrameTestFunc()

{

int a=0;

{

int b=0;

{

int c=0;

a=3;

b=4;

}

}

}



}


먼저 이전 스택영역으로 되돌아 가기전에 enter 명령어가 수행 되면 push ebp 가

기본 수행 된 다음 이전 ebp 를 넣는 처리를 하게 된다



왼쪽 굵은 글자 0x00000000 는 실제 메모리 주소를 말한다

오른쪽 주소는 해당 메모리 주소에 들어가있는 값


 

5)

0X0078F794

0X0078F798  0078F7AC   //현재 ebp

0X0078F79C  0078F7C4 //이전 ebp

0X0078F7A0  0078F7D8 //이전전 ebp

0X0078F7A4  0078F7E8 //이전전전 ebp

0X0078F7A8  0078F7F4   //이전전전전 ebp

0X0078F7AC  0078F7C4   //이전 ebp                        enter 4, 5 5)

4)

0X0078F7B0  

0X0078F7B4  0078F7C4 //현재 ebp

0X0078F7B8  0078F7D8 //이전 ebp

0X0078F7BC  0078F7E8 //이전전 ebp

0X0078F7C0  0078F7F4 //이전전전 ebp

0X0078F7C4  0078F7D8 //이전 ebp                        enter 4, 4 4)


3)

0X0078F7C8

0X0078F7CC  0078F7D8 //현재 ebp

0X0078F7D0  0078F7E8 //이전 ebp

0X0078F7D4  0078F7F4 //이전전 ebp

0X0078F7D8  0078F7E8 //이전 ebp                        enter 4, 3 3)

2)

0X0078F7DC

0X0078F7E0  0078F7E8 //현재 ebp

0X0078F7E4  0078F7F4 //이전 ebp

0X0078F7E8  0078F7F4 //이전 ebp                        enter 4, 2 2)

1)

0X0078F7EC

0X0078F7F0  0078F7F4 //현재 ebp

0X0078F7F4  0078F7FC   //이전 ebp                        enter 4, 1 1)


0)

0X0078F7F8  

0X0078F7FC  0078F8CC //이전 ebp                        enter 4, 0 0)

 










반응형
반응형
다운 받은 파일을 Microsoft Visual Studio 14.0\Common7\IDE 경로 아래다가 복사해줍니다.

usertype.dat


아래는 _asm 코드가 하이라이트 된 화면 예시




다른 설정을 하지 않았다면 이 경로 C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE 에다가 복붙
 


 

 

VS에서 도구 -> 옵션 -> 텍스트 편집기 -> 파일 확장명을 클릭한후
 
확장명에 asm을 적고 편집기에서 C++을 설정을 해줍니다.
 
확인후 VS를 재시작합니다.

 
 


http://m.todayhumor.co.kr/view.php?table=total&no=10627412








반응형
반응형
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
_asm {
        mov ebx, [ebp - 4h]    
        mov dword ptr[ebp - 4h], 10
        mov eax, [ebp - 4]
        mov ecx, ebp
                           //lea 에서 [] 은 한번 더 거처가는게 아니고 그냥 그 안에 있는 것들의 연산 결과 값이며 + 연산등을 쓸 수가 있다
        //lea eax, ecx        //lea 는 [] 이 와야만 한다 , 그냥 쓰면 이건 없는 명령어
        lea eax, [ecx + 4]    //[]를 쓰면 이 안에 사칙 연산을 쓸 수가 있게 되고 연산된 결과를 복사한다
        //mov edx, ecx + 4    //[] 없이 + 연산자 사용 하지 못함
        mov edx, ecx
        
        mov edx, [ecx]        //mov 일때 [] 는 배열 기호 [] 처럼 동작함, ecx 값을 주소로하여 ecx 주소번지에 대한 값을 가져온다
        mov edx, [ecx+4]      //mov 일때 [] 는 배열 기호 [] 처럼 동작함, ecx 값을 주소로하여 ecx 주소번지에 대한 값을 가져온다
        lea eax, dword ptr[ebp - 4]
        mov edx, dword ptr[ebp - 4]
        
    }
cs


반응형
반응형

[스택 프레임 전체 흐름]



[어셈블리 수준에서의 설명]

//원래 소스 코드
void Swap(int *parm_a, int *parm_b)
{
    int temp = 0;
    // temp 변수를 이용하여 parm_a와 parm_b의 포인터 값을 바꾼다.
    temp = *parm_a;
    *parm_a = *parm_b;
    *parm_b = temp;
}
void main()
{
    int a = 5, b = 7;
    
    // 변수 a와 b의 값을 바꾼다.
    Swap(&a, &b);
    a += 3;
    b += 4;
}
 
 
 
//어셈 코드
void Swap(int *parm_a, int *parm_b)
{
00FA16A0  push        ebp          //main의 스택 베이스 포인터를 저장한다, swap 함수가 끝나면 다시 main 함수의 스택주소 
                                   // 구간으로 이동하기 위함 여기 까지 하면 EIP, 이전 EBP 가 스택에 싸여 있게 되고
00FA16A1  mov         ebp,esp      //ebp 를 현재 함수의 스택 주소 구간으로 변경하기 위해서 현재 스택포인터 값을 베이스 포인터 값으로 바꿔준다
00FA16A3  sub         esp,0CCh  
00FA16A9  push        ebx          //edx,esi,edi 빽업
00FA16AA  push        esi                       
00FA16AB  push        edi  
00FA16AC  lea         edi,[ebp-0CCh]  
00FA16B2  mov         ecx,33h  
00FA16B7  mov         eax,0CCCCCCCCh          // 변수 공간으로 사용할 해당 구간을  CCCCCCCC 값으로 초기화 해준다
00FA16BC  rep stos    dword ptr es:[edi]      //
    int temp = 0;
00FA16BE  mov         dword ptr [temp],0  
    temp = *parm_a;
00FA16C5  mov         eax,dword ptr [parm_a]  
00FA16C8  mov         ecx,dword ptr [eax]  
00FA16CA  mov         dword ptr [temp],ecx  
    *parm_a = *parm_b;
00FA16CD  mov         eax,dword ptr [parm_a]  
00FA16D0  mov         ecx,dword ptr [parm_b]  
00FA16D3  mov         edx,dword ptr [ecx]  
00FA16D5  mov         dword ptr [eax],edx  
    *parm_b = temp;
00FA16D7  mov         eax,dword ptr [parm_b]  
    *parm_b = temp;
00FA16DA  mov         ecx,dword ptr [temp]  
00FA16DD  mov         dword ptr [eax],ecx  
}
00FA16DF  pop         edi           //함수가 끝때날 edi,esi,edx 를 pop한다
00FA16E0  pop         esi  
00FA16E1  pop         ebx  
00FA16E2  mov         esp,ebp       //스택포인터를 main 의 스택 포인터 구간으로 되돌려주어 main 함수를 계속 수행해나갈 준비를 한다
00FA16E4  pop         ebp           //swap 함수가 끝났음으로 swap 에 대한 스택공간이 필요 없됐음으로 swap 에 대한 pop ebp을 수행
//pop 명령어는 ebp 에 현재 스택 상단의 내용을 ebp 에 넣고 스택을 줄인다는 것인데, 이것은
//이전 main 함수의 스택 포인터 기준 영역으로 되돌아 간다는 의미가 된다
00FA16E5  ret           //이 함수가 콜 되면서 저장해 놓았던 이전 EIP 즉 main 의 다음 실행 주소로 복귀한다(해당 번지로 점프 하는 효과가 발생)
.......
void main()
{
00FA1700  push        ebp  
00FA1701  mov         ebp,esp  
00FA1703  sub         esp,0DCh  
00FA1709  push        ebx  
00FA170A  push        esi  
00FA170B  push        edi  
00FA170C  lea         edi,[ebp-0DCh]  
00FA1712  mov         ecx,37h  
00FA1717  mov         eax,0CCCCCCCCh  
00FA171C  rep stos    dword ptr es:[edi]  
00FA171E  mov         eax,dword ptr [__security_cookie (0FA8004h)]  
00FA1723  xor         eax,ebp  
00FA1725  mov         dword ptr [ebp-4],eax          
//메모리 할당은 작은 주소 순으로 주소가 배열되며 지역변수는 ebp 주소를 기준으로 상대적으로 변수를 할당/사용한다
    int a = 5, b = 7;
00FA1728  mov         dword ptr [a],5  
00FA172F  mov         dword ptr [b],7  
    
    Swap(&a, &b);                                    
00FA1736  lea         eax,[b]                          //swap 에 담길 인자를 스택에 넣는다
00FA1739  push        eax  
00FA173A  lea         ecx,[a]  
00FA173D  push        ecx  
00FA173E  call        Swap (0FA10F5h)                  // swap 을 call 하면서 다음 실행 주소 EIP:00FA1743  를 스택에 push 한다
00FA1743  add         esp,8  
    a += 3;
00FA1746  mov         eax,dword ptr [a]  
    a += 3;
00FA1749  add         eax,3  
00FA174C  mov         dword ptr [a],eax  
    b += 4;
00FA174F  mov         eax,dword ptr [b]  
00FA1752  add         eax,4  
00FA1755  mov         dword ptr [b],eax  
}
00FA1758  xor         eax,eax  
00FA175A  push        edx  
00FA175B  mov         ecx,ebp  
00FA175D  push        eax  
00FA175E  lea         edx,ds:[0FA178Ch]  
00FA1764  call        @_RTC_CheckStackVars@8 (0FA1253h)  
00FA1769  pop         eax  
00FA176A  pop         edx  
00FA176B  pop         edi  
00FA176C  pop         esi  
00FA176D  pop         ebx 


반응형
반응형

x86 Instruction Set Reference

LOOP/LOOPcc

Loop According to ECX Counter

-Loop 명령어를 만나게 되면 자ecx 값이 자동 감소 되고 ecx 값이 0 이 아니라면 해당 번지로 점프한다
0이면 점프 하지 않고 loop 다음 구문을 실행한다( c언어에서 for 문을 떠올리면 됨)
여기서 점프를 한다는건 일반적으로 반복 수행을 위해 loop 명령어 위쪽으로 점프한다는 것을 의미함

-ECX 외에 and 가 붙는 것들의 이해는 cmp 로 두개의 값을 비교하여 같으면 Z=1 이 세팅이 되는데 반복문의 조건문에 두개의 조건이 있다고 가정 할때 ECX 의 값과 어떤 값을 비교하는 연산이 and 로 있는 경우를 생각해 볼 수 있다
1.cmp 로 비교하여 z 값 세팅
2.이후 loopcc 로 점프할지 말지 결정
주의 loop 의 경우 점프 loop 다음 실행할 번지와 점프 뛸 곳까지의 명령어 1바이트를 벗어난 위치로 점프 할 수 없다
점프 하려면 jmp 로 그에 대한 내용은 http://codetronik.tistory.com/5 를 참고

OpcodeMnemonicDescription
E2 cbLOOP rel8Decrement count; jump short if count != 0.
E1 cbLOOPE rel8Decrement count; jump short if count != 0 and ZF=1.
E1 cbLOOPZ rel8Decrement count; jump short if count != 0 and ZF=1.
E0 cbLOOPNE rel8Decrement count; jump short if count != 0 and ZF=0.
E0 cbLOOPNZ rel8Decrement count; jump short if count != 0 and ZF=0.
Description

Performs a loop operation using the ECX or CX register as a counter. Each time the LOOP instruction is executed, the count register is decremented, then checked for 0. If the count is 0, the loop is terminated and program execution continues with the instruction following the LOOP instruction. If the count is not zero, a near jump is performed to the destination (target) operand, which is presumably the instruction at the beginning of the loop. If the address-size attribute is 32 bits, the ECX register is used as the count register; otherwise the CX register is used.

The target instruction is specified with a relative offset (a signed offset relative to the current value of the instruction pointer in the EIP register). This offset is generally specified as a label in assembly code, but at the machine code level, it is encoded as a signed, 8-bit immediate value, which is added to the instruction pointer. Offsets of -128 to +127 are allowed with this instruction.

Some forms of the loop instruction (LOOPcc) also accept the ZF flag as a condition for terminating the loop before the count reaches zero. With these forms of the instruction, a condition code (cc) is associated with each instruction to indicate the condition being tested for. Here, the LOOPcc instruction itself does not affect the state of the ZF flag; the ZF flag is changed by other instructions in the loop.

Operation
if(AddressSize == 32) Count = ECX;
else Count = CX; //AddressSize == 16

Count = Count - 1;

switch(Instruction) {
	case LOOPE:
	case LOOPZ:
		if(ZF == 1 && Count != 0) BranchCond = 1;
		else BranchCond = 0;
		break;
	case LOOPNE:
	case LOOPNZ:
		if(ZF == 0 && Count != 0) BranchCond = 1;
		else BranchCond = 0;
		break;
	default: //LOOP
		if(Count != 0) BranchCond = 1;
		else BranchCond = 0;
		break;
}
if(BranchCond == 1) {
	EIP = EIP + SignExtend(Destination);
	if(OperandSize == 16) EIP = EIP & 0xFFFF;
	else /*OperandSize == 32*/ if(EIP < CS.Base || EIP < CS.Limit) Exception(GP);
}
else ResumeExecution(); //Terminate loop and continue program execution at EIP
Flags affected

None.

Protected Mode Exceptions
#GP(0)If the offset being jumped to is beyond the limits of the CS segment.
Real-Address Mode Exceptions
#GPIf the offset being jumped to is beyond the limits of the CS segment or is outside of the effective address space from 0 to FFFFH. This condition can occur if a 32-bit address size override prefix is used.
Virtual-8086 Mode Exceptions
Same exceptions as in Real Address Mode
InstructionLatencyThroughputExecution Unit
CPUID0F3n/0F2n/069n0F3n/0F2n/069n0F2n
LOOP81.5ALU

http://x86.renejeschke.de/html/file_module_x86_id_161.html


반응형
반응형

상태 레지스터 또는 플래그 레지스터는 마이크로프로세서에서 다양한 산술 연산 결과의 상태를 알려주는 플래그 비트들이 모인 레지스터이다.

주로, 조건문과 같은 실행 순서의 분기에 사용된다.


상태 레지스터 플래그

상태 레지스터에는 다음과 같은 플래그들이 있다.

플래그 기호이름의미
Z제로 플래그연산 결과가 0일 경우에 참이 된다.
C캐리 플래그부호 없는 숫자의 연산 결과가 비트 범위를 넘어섰을 때 참이 된다.
A보조 캐리 플래그연산 결과 하위 니블(4bits)에서 비트 범위를 넘어섰을 때 참이 된다. 이진화 십진법(BCD) 연산에 사용된다.
V / O / W오버플로 플래그부호 있는 숫자의 연산 결과가 비트 범위를 넘어섰을 때 참이 된다.
N / S네거티브 플래그, 사인 플래그연산 결과가 음수일 때 참이 된다.
I / E인터럽트 플래그이 플래그가 참일 경우에만 인터럽트 요구를 받아들인다. 일반적으로 관리자 모드에서만 값을 변경 할 수 있다.
P패리티 플래그연산 결과에서 1로된 비트의 수가 짝수일 경우 참이 된다.
D디렉션 플래그문자열 조작에서 참일 경우 주소 레지스터 값이 자동으로 감소하고, 거짓일 경우 자동으로 증가한다.
D / T디버그 플래그, 트랩 플래그참일 경우 한 명령이 실행할 때마다 인터럽트가 발생한다. 디버깅에 사용된다.



https://ko.wikipedia.org/wiki/%EC%83%81%ED%83%9C_%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0

반응형
반응형


점프 할때의 플래그들 정리

비슷한 의미 별로 그룹화 시켜놓은것들, 필요 할 때 참고삼아


Getting the sense for jumps and flags has long been a troublesome area for me, especially since the Intel assembler book shows 32 of these, all with similar-sounding names. Looking more closely I found that many of the instructions were synonyms for each other, and in practice the whole gamut is not needed, and in the process found that my copy of Intel's 80386 Programmer's Reference Manual gave an incorrect description for one of the instructions.

So I have grouped these functionally, with all instruction synonyms in the same row.

InstructionDescriptionsigned-nessFlagsshort 
jump 
opcodes
near 
jump 
opcodes
JOJump if overflow OF = 1700F 80
JNOJump if not overflow OF = 0710F 81
JSJump if sign SF = 1780F 88
JNSJump if not sign SF = 0790F 89
JE 
JZ
Jump if equal 
Jump if zero
 ZF = 1740F 84
JNE 
JNZ
Jump if not equal 
Jump if not zero
 ZF = 0750F 85
JB 
JNAE 
JC
Jump if below 
Jump if not above or equal 
Jump if carry
unsignedCF = 1720F 82
JNB 
JAE 
JNC
Jump if not below 
Jump if above or equal 
Jump if not carry
unsignedCF = 0730F 83
JBE 
JNA
Jump if below or equal 
Jump if not above
unsignedCF = 1 or ZF = 1760F 86
JA 
JNBE
Jump if above 
Jump if not below or equal
unsignedCF = 0 and ZF = 0770F 87
JL 
JNGE
Jump if less 
Jump if not greater or equal
signedSF <> OF7C0F 8C
JGE 
JNL
Jump if greater or equal 
Jump if not less
signedSF = OF7D0F 8D
JLE 
JNG
Jump if less or equal 
Jump if not greater
signedZF = 1 or SF <> OF7E0F 8E
JG 
JNLE
Jump if greater 
Jump if not less or equal
signedZF = 0 and SF = OF7F0F 8F
JP 
JPE
Jump if parity 
Jump if parity even
 PF = 17A0F 8A
JNP 
JPO
Jump if not parity 
Jump if parity odd
 PF = 07B0F 8B
JCXZ 
JECXZ
Jump if %CX register is 0 
Jump if %ECX register is 0
 %CX = 0 
%ECX = 0
E3 

Processor Flags

The x86 processors have a large set of flags that represent the state of the processor, and the conditional jump instructions can key off of them in combination.

CF - carry flag(c에서는 CY)
Set on high-order bit carry or borrow; cleared otherwise
PF - parity flag(c에서는 PE)
Set if low-order eight bits of result contain an even number of "1" bits; cleared otherwise
ZF - zero flags(c에서는 ZR)
Set if result is zero; cleared otherwise
SF - sign flag(c에서는 PL이던디)
Set equal to high-order bit of result (0 if positive 1 if negative)
OF - overflow flag(c에서는 OV)
Set if result is too large a positive number or too small a negative number (excluding sign bit) to fit in destination operand; cleared otherwise



http://unixwiz.net/techtips/x86-jumps.html


반응형
반응형

mov eax,0                    //mov 명령어는 ZR 플래그를 조작하는 명령어가 아님

cmp eax,0 //두개의 값이 같으면 Z(ZR) 에 1을 세팅함

je          main //ZR값이 1 이면 점프 , jz 도 ZR 이 1 이면 점프,  jz==je 이 둘은 같은 동작을 한다


jz 는 eax 값이 증가 했다가 감소 해서 0 이 되면 가 1이 된다는 관점

je 는 cmp 로 두개를 비교하여 같으면 Z 가 1 이 된다는 관점


jne = jump not equal 로 Z가 0 일때 점프 한다

jze 가 0 일 때 점프



cmp A, B

JA  : 앞에 것이 크면 점프 (Above)

JB  : 앞에 것이 작으면 점프(Below)


C : Carry 비트(더하기, 자리 올림)가 1이 됨 1111 + 1    또는 자리내림(빼기(1-2=-1))  일때 C 가 1이 됨


cmp 연산에서 cmp a,b 는 a-b 연산을 하는대 이때 C 비트가 변경 된다





[부호가 없는 데이터 비교, 제일 앞의 비트또한 숫자로 처리한다]

JA 의 경우 C가 0이고 ZR 이 0 일 때 점프 한다 

cmp 는 A-B 연산을 하는데 두 값이 같다면 A-B=0 , A>B 의 경우 결과는 양수이고 A 보다 

결과가 작음으로 자리 올림은 발생 하지 않으며 ZR 은 두 값이 같지 않음으로 0 이 된다


JB 의 경우 C 가 1일때 점프 한다 

ZR 은 0 이든 1이든 상관 없는데 그 이유는 A-B 결과가 음수가 되면서 이로 인해 자리내림으로 C 가 1이 되어서 

이것으로 점프를 할지 말지 구분하면 됨


[부호가 없는 데이터 비교, 제일 앞의 비트를 부호로 처리한다]

JG  

JL


JA, JG 가 같은 맥락인데 어떤 명령어를 사용 하느냐에 따라서 비트는 같지만 비트를 해석하는 방식이 달라진다




JNA == JBE





jc : carry 플래그 값만 보고도 점프가 가능한데(CY)

jo : overflow bit 가 1 일때 (OV)

js : sign 비트가 1 일때 (PL)


pl : 연산 값이 음수인경우 1 , 양수면  0

ov : char s=127

s+=1 == -128 이 되는데 이때 부호 비트까지 연산이 되어버리는 경우 ov 에 1이 세팅 됨
 




(c에서는 AC 가 보조 캐리비트)

 cmp edx,eax 했을 때 cmp 한 연산 결과의 하위 4bit 에 대해 올림이 발생하면 그때 1이 됨

   [BCD : 2진수 4자리를 묶어 10진수 한자리로 표현 하는 법]

           16진수 표현 시 10=a~ 15=f 로 표현 되는데  이렇게 표현 하는 방식을 말함

그리하여 4bit까지 체크 하기 위한 비트가 AC 보조 캐리 비트다, 즉 15가 넘어 가게 될 경우 AC=1 이 된다(f에 대한 자리 올림)

ex) mov eax , 15

inc eax



CF - carry flag(c에서는 CY)
Set on high-order bit carry or borrow; cleared otherwise
PF - parity flag(c에서는 PE, 연산될 결과에서 하위 8bit에 대해 인텔은 홀 수 비트 개수를 유지하기 위해 여기에 1 또는 0 을 채운다
                                   cmp edx,eax 했을 때 cmp 한 연산 결과의 하위 8bit 에 대해 체크)
Set if low-order eight bits of result contain an even number of "1" bits; cleared otherwise

ZF - zero flags(c에서는 ZR)
Set if result is zero; cleared otherwise
SF - sign flag(c에서는 PL이던디)
Set equal to high-order bit of result (0 if positive 1 if negative)
OF - overflow flag(c에서는 OV)
Set if result is too large a positive number or too small a negative number (excluding sign bit) to fit in destination operand; cleared otherwise



반응형
반응형


먼저 최빈 값이란?


자료 중에서 가장 많이 출현한 값을 말한다, 최고의 빈도수를 보이는 값, (빈도수 : 같은 일이 반복되는 도수)





파이썬을 이용하여 최빈값(mode)를 구하기 위해서는 collections 모듈의 Counter 클래스를 알고 있어야 한다. Counter는 사전(dict) 클래스의 하위 클래스로 리스트나 튜플에서 각 데이터가 등장한 횟수를 사전 형식으로 돌려준다. 예를 들면 다음과 같다.

>>> from collections import Counter
>>> colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
>>> cnt = Counter(colors)
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

또한 Counter 클래스의 most_common() 메쏘드는 등장한 횟수를 내림차순으로 정리하여 다음과 같이 보여준다. 

>>> numbers = [1, 2, 3, 3, 4, 4, 4, 5, 5]
>>> from collections import Counter
>>> cnt = Counter(numbers)
>>> cnt.most_common()
[(4, 3), (3, 2), (5, 2), (1, 1), (2, 1)]

리스트(list)를 구성하는 요소들은 튜플(tuple)인데, 각 튜플의 첫 번째 요소는 numbers에 등장하는 숫자이고, 두 번째 요소는 각 숫자가 등장한 횟수이다. 만약 등장한 횟수가 같은 수들은 임의의 순서로 정렬되어 보여지게 된다. 만약 상위 3개의 결과만을 원한다면 다음과 같이 하면 된다. 

>>> cnt.most_common(3)
[(4, 3), (3, 2), (5, 2)]

최빈값을 얻어내고 싶다면 다음과 같이 하면 된다.

>>> mode = cnt.most_common(1)
>>> mode
[(4, 3)]
>>> mode[0][0]
4

자 이제 최빈값을 찾아내는 함수를 만든다면 다음과 같은 형태가 될 것이다. 

from collections import Counter

def modefinder(numbers):   #numbers는 리스트나 튜플 형태의 데이터
    c = Counter(numbers)
    mode = c.most_common(1)
    return mode[0][0]

만약 최빈수가 2개 이상 존재한다면 다음과 같이 함수를 만들 수 있다.

from collections import Counter

def modefinder(numbers):
    c = Counter(numbers)
    order = c.most_common()
    maximum = order[0][1]

    modes = []
    for num in order:
        if num[1] == maximum:
            modes.append(num[0])
    return modes

위와 같이 하면 최빈값들이 리스트의 형태로 modes에 저장되어 리턴 된다. 


http://codepractice.tistory.com/71


반응형
반응형

cmd 창 띄우고 

python -m pip install -U pip setuptools
python -m pip install matplotlib


하면 다운 받고 알아서 설치 됨



http://matplotlib.org/users/installing.html

반응형
반응형

map


map(f, iterable)은 함수(f)와 반복 가능한(iterable) 자료형을 입력으로 받는다. map은 입력받은 자료형의 각 요소가 함수 f에 의해 수행된 결과를 묶어서 리턴하는 함수이다.

다음의 예를 보자.

# two_times.py
def two_times(numberList):
    result = [ ]
    for number in numberList:
        result.append(number*2)
    return result

result = two_times([1, 2, 3, 4])
print(result)

two_times 함수는 리스트 요소를 입력받아 각 요소에 2를 곱한 결과값을 돌려준다. 실행 결과는 다음과 같다.

결과값: [2, 4, 6, 8]

위의 예제는 map 함수를 이용하면 다음처럼 바꿀 수 있다.

>>> def two_times(x): return x*2
...
>>> list(map(two_times, [1, 2, 3, 4]))   # map(함수, 반복가능한 자료형)
[2, 4, 6, 8]

이제 앞 예제를 해석해 보자. 먼저 리스트의 첫 번째 요소인 1이 two_times 함수의 입력값으로 들어가고, 1 * 2의 과정을 거쳐서 2가 된다. 다음으로 리스트의 두 번째 요소인 2가 2 * 2의 과정을 거쳐 4가 된다. 따라서 결과값 리스트는 이제 [2, 4]가 된다. 총 4개의 요소값이 모두 수행되면 최종적으로 [2, 4, 6, 8]이 리턴된다. 이것이 map 함수가 하는 일이다.

(※ 위 예에서 map의 결과를 리스트로 보여 주기 위해 list 함수를 이용하여 출력하였다. 파이썬 2.7은 map의 결과가 리스트이므로 위 예에서 list 함수를 이용하여 리스트로 변환하지 않아도 된다.)

앞의 예는 lambda를 사용하면 다음처럼 간략하게 만들 수 있다.

>>> list(map(lambda a: a*2, [1, 2, 3, 4]))
[2, 4, 6, 8]

map 함수 예를 하나 더 살펴보자.

# map_test.py
def plus_one(x):
    return x+1
print(list(map(plus_one, [1, 2, 3, 4, 5])))

결과값: [2, 3, 4, 5, 6]

위 예는 map과 plus_one 함수를 이용하여 리스트의 각 요소값을 1씩 증가시키는 예제이다.


http://blog.naver.com/da91love/220840312865

반응형
반응형
최근 들어 파이선을 좀 공부해보고 있는데 이것ㅈ 저것과 잘 연동이 되는 부분이 파이썬의 유저인 분들에게 메리트가 있는 부분이라는 생각이 든다



https://www.youtube.com/watch?v=a3ufXZ9L6BM

Python은 과학 계산 분야에서도 이미 널리 사용되고 있습니다. numpy와 scipy 기반으로 만들어진 많은 모듈들이 휼륭한 생태계를 이루고 있기 때문입니다. 그러나 극한의 계산 성능을 요구하는 분야(HPC, High Performance Computing)에서는 여전히 C와 Fortran으로만으로 짜여진 코드들이 선호되고 있습니다. 이런 분야에서 Python에 대한 일반적인 견해는 전처리/후처리에는 유용하지만 메인 코드에 적용하기에는 느리다라는 것입니다.

이번 발표에서는 HPC 분야에서도 Python의 유용함을 보여줍니다. 계산이 집중된 부분만을 Fortran, C로 구현하여 Python 메인 코드에 접합하면, Python의 장점은 충분히 활용하면서도 계산 성능에 큰 손해는 보지 않을 수 있습니다. 게다가 CUDA-C, OpenCL-C와 연동하면 GPU, MIC와 같은 가속 프로세서들도 비교적 쉽게 활용할 수 있습니다. 이번 발표에서는 간단한 시뮬레이션 코드를 예제로 사용하여 Python 코드로부터 시작하여 Fortran, C, CUDA-C, OpenCL-C 등을 단계적으로 접합해 나가는 것을 보여줄 것입니다.




반응형
반응형

파이썬에서 밑줄 하나(_)는 무슨 기능인가요?


인터넷에서 이런 코드를 봤는데 문자열 "_"도 아니고 for _ in에 _는 뭐하는건지 궁금합니다.

소스코드

mylist = [1,1]

if True:
    for _ in mylist:
        print("hello world!")

출력

hello world
hello world




 예제 소스코드로 보면 리스트의 요소 개수만큼 이터레이션은 하지만 요소를 가져다가 쓰지 않기 때문에 굳이 변수를 사용하지 않고 _로 요소값을 버린다고 생각하시면 쉬울거 같네요.



https://goo.gl/8AFvGC

반응형
반응형

먼저 람다 기본 구문 

https://wikidocs.net/32

lambda

lambda는 함수를 생성할 때 사용하는 예약어로, def와 동일한 역할을 한다. 보통 함수를 한줄로 간결하게 만들 때 사용한다. 우리말로는 "람다"라고 읽고 def를 사용해야 할 정도로 복잡하지 않거나 def를 사용할 수 없는 곳에 주로 쓰인다. 사용법은 다음과 같다.

lambda 인수1, 인수2, ... : 인수를 이용한 표현식

한번 직접 만들어 보자.

>>> sum = lambda a, b: a+b
>>> sum(3,4)
7

lambda를 이용한 sum 함수는 인수로 a, b를 받아 서로 더한 값을 돌려준다. 위의 예제는 def를 사용한 아래 함수와 하는 일이 완전히 동일하다.

>>> def sum(a, b):
...     return a+b
...
>>>

그렇다면 def가 있는데 왜 lambda라는 것이 나오게 되었을까? 이유는 간단하다. lambda는 def 보다 간결하게 사용할 수 있기 때문이다. 또한 lambda는 def를 사용할 수 없는 곳에도 사용할 수 있다. 다음 예제에서 리스트 내에 lambda가 들어간 경우를 살펴보자.

>>> myList = [lambda a,b:a+b, lambda a,b:a*b]
>>> myList
[at 0x811eb2c>, at 0x811eb64>]

즉, 리스트 각각의 요소에 lambda 함수를 만들어 바로 사용할 수 있다. 첫 번째 요소 myList[0]은 2개의 입력값을 받아 두 값의 합을 돌려주는 lambda 함수이다.

>>> myList[0]
at 0x811eb2c>
>>> myList[0](3,4)
7

두 번째 요소 myList[1]은 2개의 입력값을 받아 두 값의 곱을 돌려주는 lambda 함수이다.

>>> myList[1](3,4)
12

파이썬에 익숙해질수록 lambda 함수가 굉장히 편리하다는 사실을 알게 될 것이다.



map

map(f, iterable)은 함수(f)와 반복 가능한(iterable) 자료형을 입력으로 받는다. map은 입력받은 자료형의 각 요소가 함수 f에 의해 수행된 결과를 묶어서 리턴하는 함수이다.

다음의 예를 보자.

# two_times.py
def two_times(numberList):
    result = [ ]
    for number in numberList:
        result.append(number*2)
    return result

result = two_times([1, 2, 3, 4])
print(result)

two_times 함수는 리스트 요소를 입력받아 각 요소에 2를 곱한 결과값을 돌려준다. 실행 결과는 다음과 같다.

결과값: [2, 4, 6, 8]

위의 예제는 map 함수를 이용하면 다음처럼 바꿀 수 있다.

>>> def two_times(x): return x*2
...
>>> list(map(two_times, [1, 2, 3, 4]))
[2, 4, 6, 8]

이제 앞 예제를 해석해 보자. 먼저 리스트의 첫 번째 요소인 1이 two_times 함수의 입력값으로 들어가고, 1 * 2의 과정을 거쳐서 2가 된다. 다음으로 리스트의 두 번째 요소인 2가 2 * 2의 과정을 거쳐 4가 된다. 따라서 결과값 리스트는 이제 [2, 4]가 된다. 총 4개의 요소값이 모두 수행되면 최종적으로 [2, 4, 6, 8]이 리턴된다. 이것이 map 함수가 하는 일이다.

(※ 위 예에서 map의 결과를 리스트로 보여 주기 위해 list 함수를 이용하여 출력하였다. 파이썬 2.7은 map의 결과가 리스트이므로 위 예에서 list 함수를 이용하여 리스트로 변환하지 않아도 된다.)

앞의 예는 lambda를 사용하면 다음처럼 간략하게 만들 수 있다.

>>> list(map(lambda a: a*2, [1, 2, 3, 4]))
[2, 4, 6, 8]

map 함수 예를 하나 더 살펴보자.

# map_test.py
def plus_one(x):
    return x+1
print(list(map(plus_one, [1, 2, 3, 4, 5])))

결과값: [2, 3, 4, 5, 6]

위 예는 map과 plus_one 함수를 이용하여 리스트의 각 요소값을 1씩 증가시키는 예제이다.

반응형
반응형

자식 클래스에서 특별히 필요하지 않으면 복사 생성자를 생성하지 않고 디폴트 복사 생성자를 이용할 수 있다. 컴파일러는 복사 생성자가 정의되지 않으면 알아서 디폴트 복사 생성자를 생성한다. 그러나 깊은 복사를 위해 직접적으로 복사 생성자를 정의한다고 할 때, 자식 클래스에서 부모 클래스의 복사 생성자를 명시적으로 호출해주지 않을 경우 부모 클래스의 멤버에 대해 복사 생성자가 호출되지 않고 디폴트 생성자가 호출되는데 그친다.


#include <iostream>
 
using namespace std;
 
class Parent
{
private:
    int x;
 
public:
    Parent(int n = 0) : x(n) {}
    Parent(const Parent& copy) : x(copy.x) {}
 
    int getX() { return x; }
};
 
class Child : public Parent
{
private:
    int y;
 
public:
    Child(int n1 = 0, int n2 = 0) : Parent(n1), y(n2) {}
    Child(const Child& copy) : y(copy.y) {}
 
    int getY() { return y; }
};
 
int main(void)
{
    Child c1(1);
    Child c2(c1);
     
    cout << c1.getX() << ',' << c1.getY() << endl;
    cout << c2.getX() << ',' << c2.getY() << endl;
 
    return 0;
}



1,0

0,0


 부모 클래스의 멤버에 대해 정상적으로 복사 생성자가 호출되기 위해 자식 클래스의 복사 생성자에서 명시적으로 부모 클래스의 복사 생성자를 호출해주자.


1
Child(const Child& copy) : Parent(copy), y(copy.y) {}

1,0

1,0


출처 http://wonthing86.tistory.com/59

반응형
반응형


 

 클로져 객체의 복사 생성자와 소멸자

 




모든 클로져 객체들은 암묵적으로 정의된 복사 생성자(copy constructor)와 소멸자(destructor)를 가지고 있습니다. 이 때 클로져 객체가 복사 생성 될 때 값으로 Capture 된 것들의 복사 생성이 일어나겠지요. 아래의 예를 한번 보도록 하겠습니다.


일단 


struct trace

{

trace() : i(0) { cout << "construct\n"; }

trace(trace const &) { cout << "copy construct\n"; }

~trace() { cout << "destroy\n"; }

trace& operator=(trace&) { cout << "assign\n"; return *this;}

int i;

};


와 같이 생성, 복사 생성, 소멸, 그리고 대입 연산을 확인할 수 있는 trace 라는 구조체를 정의해놓고 


trace t;

int i = 8;


auto f = [=]() { return i / 2; };


를 한다면 어떻게 나올까요? f 에서 t 를 사용하지 않았으므로, t 를 Capture 하지 않게 됩니다. 따라서 그냥



이 나오게 됩니다.


그렇다면 아래의 예는 어떨까요


trace t;

int i = 8;


auto m1 = [=]() { int i = t.i; };

cout << " --- make copy --- " << endl;


auto m2 = m1;


먼저 m1 을 생성하면서, 람다가 t 를 Capture 하였으므로 t 의 복사 생성자가 호출되게 됩니다. 왜냐하면 값으로 받았기 때문이지요. 만일 레퍼런스로 받았다면 복사 생성자가 호출되지 않았을 것입니다 (확인해보세요!) 그리고 아래의 auto m2 = m1; 에서 클로져 객체의 복사 생성이 일어나는데, 이 때, 클로져 객체의 복사 생성자가 값으로 Capture 된 객체들을 똑같이 복사 생성 해주게 됩니다. 따라서 또 한번 t 의 복사 생성자가 호출되겠지요. 그 결과 아래와 같이 출력됩니다.






ref : http://itguru.tistory.com/196 

반응형
반응형

Circular references


http://sweeper.egloos.com/viewer/2826435

http://goo.gl/B1mEP9\


 

9) Circular references

레퍼런스 카운팅 기반이기에 순환 참조에 대한 잠재적인 문제가 있을 수 있다.
즉, A와 B가 서로에 대한 shared_ptr을 들고 있으면 레퍼런스 카운트가 0이 되지 않아 메모리가 해제되지 않는다.

게임의 경우를 예로 들어, 파티 객체가 있으면 파티원 객체가 있을 것이다.
파티 객체는 파티원 객체를 리스트 형태로 들고 있고, 또 파티원도 자기가 속한 파티 객체를 알기 위해 참조 형태로 들고 있는 예제를 살펴보자.

  1. #include <memory>    // for shared_ptr
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. class User;
  7. typedef shared_ptr<User> UserPtr;
  8.  
  9. class Party
  10. {
  11. public:
  12.     Party() {}
  13.     ~Party() { m_MemberList.clear(); }
  14.  
  15. public:
  16.     void AddMember(const UserPtr& member)
  17.     {
  18.         m_MemberList.push_back(member);
  19.     }
  20.  
  21. private:
  22.     typedef vector<UserPtr> MemberList;
  23.     MemberList m_MemberList;
  24. };
  25. typedef shared_ptr<Party> PartyPtr;
  26.  
  27. class User
  28. {
  29. public:
  30.     void SetParty(const PartyPtr& party)
  31.     {
  32.         m_Party = party;
  33.     }
  34.  
  35. private:
  36.     PartyPtr m_Party;
  37. };
  38.  
  39.  
  40. int _tmain(int argc, _TCHAR* argv[])
  41. {
  42.     PartyPtr party(new Party);
  43.  
  44.     for (int i = 0; i < 5; i++)
  45.     {
  46.         // 이 user는 이 스코프 안에서 소멸되지만,
  47.         // 아래 party->AddMember로 인해 이 스코프가 종료되어도 user의 refCount = 1
  48.         UserPtr user(new User);
  49.  
  50.         // 아래 과정에서 순환 참조가 발생한다.
  51.         party->AddMember(user);
  52.         user->SetParty(party);
  53.     }
  54.  
  55.     // 여기에서 party.reset을 수행해 보지만,
  56.     // 5명의 파티원이 party 객체를 물고 있어 아직 refCount = 5 의 상태
  57.     // 따라서, party가 소멸되지 못하고, party의 vector에 저장된 user 객체들 역시 소멸되지 못한다.
  58.     party.reset();
  59.  
  60.     return 0;
  61. }

위와 같은 형태로 shared_ptr이 서로를 참조하고 있는 것은 circular reference라고 한다.

위 예제처럼, 그룹 객체 - 소속 객체간 상호 참조는 실무에서도 흔히 볼 수 있는 패턴이며, 
보통은 위 예제처럼 직접 참조 형식이 아니라, User는 PartyID를 들고 있고, Party 객체에 접근 필요시 PartyManger(컬렉션)에 질의해서 유효한 Party 객체 포인터를 얻어오는 방식을 사용한다.

그렇다고, PartyManager에 일일히 ID로 검색하는 비용을 줄이고자, Party 포인터를 직접 들고 있으면, 들고 있던 포인터가 dangling pointer가 될 수 있는 위험이 있다.

이럴 때, User 객체가 Party 객체를 shared_ptr가 아닌 weak_ptr을 사용하여 들고 있다면, 검색 비용 회피와 dangling pointer의 위험에서 모두 벗어날 수 있다.

std::weak_ptr은 shared_ptr로부터 생성될 수 있고, shared_ptr이 가리키고 있는 객체를 똑같이 참조하지만, 참조만 할 뿐 reference counting은 하지 않아 위 예제의 목적에 가장 바람직한 대안이 될 수 있다 할 수 있다.






반응형
반응형
가변 템플릿은 c 에서 가변인자 함수에서

#include <iostream>
using namespace std;
template <typename T>
void print(const T& t)
{
cout << t << endl;
}
template <typename First, typename... Rest>
void print(const First& first, const Rest&... rest)
{
cout << first << ", ";
print(rest...); // recursive call using pack expansion syntax
}
int main()
{
print(100, 200, 201, 202, 300);
print("first", 2, "third", 3.14159);
}










//실행 결과

100, 200, 201, 202, 300

first, 2, third, 3.14159


참고 : https://msdn.microsoft.com/ko-kr/library/dn439779(v=vs.140).aspx




http://egloos.zum.com/Lusain/v/3158201



C에서는 va_list 사용하여 가변인자를 처리해야 했다.

 

va_start 시작해서 va_end 끝내야 했으며어떤 타입인지 미리 알려주어야 하거나 모든 같은 형으로 가변인자를 사용해야 했다.불편했고, C 마지막에 printf scanf 동작원리로 배운 뒤로는   적이 없던 개념이다.

 

C++ 와서 template 이라는 개념이 생겼다어떤 형태라도 template으로 뭉뚱그려 인자로 받을  있게  것이다그리고 가변인자역시 template, 탬플릿으로 받을  있다.

 

가변인자 탬플릿은 다음과 같이 선언한다.

 

template<typename  첫번째_가변인자_인수>

반환형 함수명(첫번째_가변인자_인수... 가변인자_변수);

 

타입이름 앞에 ...  붙여 가변인자 탬플릿이라고 알려준다.

한글로  이름은 원하는 타입을 적으면 된다이렇게.

 

template<typename... Args>

void print(Args... args)

{

...

print(args...);

}

 

매개변수로  경우 변수명의  ... 붙여준다.

 

탬플릿 선언 : typename 뒤에 : typename... Ty

선언 : 타입의  ... : void print(Ty... ty);

사용 : 변수의  ... : print(ty...);

 

 

그런데 이렇게 쓰면 가변 인자의 내용을 확인을  하기 때문에 다음과 같이 ' 번째 가변 인자' 명시한다.

 

template<typename  첫번째_가변인자_인수typename... 가변인자_타입이름>

반환형  함수명( 첫번째_가변인자_인수 변수명가변인자_타입이름... 가변인자_변수);

 

예를 들면 이렇게 적으면 된다.

 

template<typename  Tytypename ... Args>

void print(Ty ty, Args...args)

 

'가변인자_변수'  번째 인자를 제외한 남은 가변인자를 가지고 '첫번째_가변인자_인수'  번째 인자로 들어가게 된다이걸재귀적으로 시행하는 것이 가변인자 함수의 핵심이다.

 그런데  예제에서는 Ty라는 탬플릿으로 인자를 받았기 때문에 Ty 어떤 타입인지   없다. C++ 공부한 사람들이라면  사용할 만한 좋은 개념을  것이다.

 함수 오버로딩(overloading : 매개인자에 따라 함수명이 동일한 함수들을 재정의하는 기능) 사용하는 것이다.

 

그러면 사용 예는 다음과 같아진다.

 

void printType(int i);

void printType(string s);

...

 

template<typename  Tytypename ... Args>

void print(Ty ty, Args...args)

{

printType(ty);

print(args...);

}

 

이쯤에서 의문이 하나 생긴다가변인자가 하나씩 빠진 끝에 가변인자가 하나도 남지 않을 경우에는?

 

가변인자 탬플릿을 사용할 경우위와 같은 문제를 해결하기 위해 매개인자가 없거나마지막에  매개인자를 가지는

"가변인자탬플릿 함수와 동일한 함수 이름을 가지는" 함수를 오버로딩 해야 한다.

  함수는 가변인자를 모두 처리한 뒤의 후처리를 위한 함수로, C에서의 va_end()  동일한 역할을 수행한다

차이점은, va_end() 없다고 컴파일 에러를 부르지 않지만 가변인자 탬플릿은원하는 형식의 함수가 오버로딩되지 않으면 컴파일 오류 뿜는다.


















반응형
반응형

블로그 이미지


operator 는 상속되지 않는다



그래서 다음과 같은 에러를 벹는다


class ttt

{

public :


void operator=(int a) {

std::cout  << "ttttt "<< a << std::endl;

}

};



class ddd : public ttt

{

public :

};



int main()

{


ddd d1;

d1.operator=(10);



오류 C2664 'ddd &ddd::operator =(ddd &&)': 인수 1을(를) 'int'에서 'const ddd &'(으)로 변환할 수 없습니









그런데 c++ 11 에서부터 생성자를 상속 받을 수 있는 상속생성자 using 을 제공하는데


이때 operator 또한 상속 받을 수 있게 지원해준다



class ttt

{

public :


void operator=(int a) {

std::cout  << "ttttt "<< a << std::endl;

}


};



class ddd : public ttt

{


public :


using ttt::operator=;

};



int main()

{


ddd d1;

d1.operator=(10);


return 0;

}


좀 더 자세한 using 은 http://3dmpengines.tistory.com/1606 상속 생성자를 참고..

반응형
반응형



상속생성자란 기본클래스에 정의된 생성자를 상속받는 클래스에서 상속받을 수 있도록 하는 기능이다.


http://yesarang.tistory.com/374

상속생성자는 컴파일러가 기본생성자와 복사생성자를 생성하는 규칙 때문에 발생하는 문제점을 해결하기 위한 기능이므로 우선 이 규칙을 이해할 필요가 있다. C++ 컴파일러는 프로그래머가 생성자를 정의하지 않으면 기본 생성자 및 복사생성자를 알아서 생성한다. 예를 들어,

class B {
 int v_;

public:
 int get();
 void set(int v);
};

B b;

와 같은 코드가 아무런 문제 없이 컴파일되는 이유는 컴파일러가 기본생성자를 생성해 주기 때문이다. 그런데 B를 쓰다 보면 기본생성자에 의해 초기화되지 않은 멤버 변수 값 때문에 문제가 생기는 경우가 있기 마련이다. 예를 들어,

void f();

B b;
f(b.get());

와 같은 코드를 실행할 경우 b.v_에 담긴 쓰레기 값 때문에 문제가 발생할 수 있을 것이다. 이런 문제를 발견했을 때 상식있는 프로그래머라면 다음과 같이 생성자를 추가할 것이다.

class B {
 int v_;

public:
 B(int v) : v_(v) {}
 int get();
 void set(int v);
};

B b;

그러면 당장 다음과 같은 에러가 발생하게 된다.

error C2512: 'B' : 사용할 수 있는 적절한 기본 생성자가 없습니다.

그렇다. 프로그래머가 기본생성자가 아닌 생성자를 하나라도 추가하면 컴파일러가 기본생성자를 생성하지 않는 것이다. 이제 프로그래머가 직접 기본생성자를 작성해야 한다.

class B {
 int v_;

public:
 B() : B(0) {} // C++11의 위임생성자 기능 활용
 B(int v) : v_(v) {}
 int get();
 void set(int v);
};

그런데 만약 B로부터 상속 받은 D라는 클래스가 있었다고 생각해 보자.

class D : public B {
public:
 void compute();
};

B::B(int)가 추가된 이유를 이해하는 프로그래머라면 D를 사용할 때 다음과 같이 생성시 초기값을 제대로 지정하려고 할 것이다.

D d(10);

그렇지만 위 코드는 컴파일 에러를 발생시킨다. 왜냐하면 D::D(int)는 애초에 정의되어 있지 않기 때문이다. 결국 D를 작성한 프로그래머는 다음과 같이 D::D(int)를 추가해야 한다.

class D : public B {
public:
 D(int v) : B(v) {}
 void compute();
};

D d(10);

그렇다면 다음 코드는 어떨까?

D d2;
d2.set(10);

D::D(int)가 없었기 때문에 충분히 여러 차례 사용될만한 코드 패턴일 것이다. 그렇지만 D를 작성한 프로그래머가 D::D(int)를 추가한 순간 위와 같은 코드 패턴들은 모두 컴파일 에러를 일으키게 된다. D 클래스를 작성한 프로그래머와 위 코드를 작성한 프로그래머가 같다면 별 문제 없겠지만 다르다면 사무실 어느 구석에선가 “악~”하고 소리가 날 일이다. 결국 D는 다음과 같이 작성되어야 한다.

class D : public B {
public:
 D() : B() {}
 D(int v) : B(v) {}
 void compute();
};

D d(10);
D d2;
d2.set(10);

창조적 귀차니즘이 있는 프로그래머라면 이쯤에서 의문이 하나 생긴다. “왜 이렇게 불편하게 해 놓았지? 애초에 DB의 생성자들을 다 물려받으면 되잖아. 상속에는 생성자 상속까지 포함되어야 하는 거 아닌가?”

상속생성자는 이런 의문에서 출발한 기능이다. 위 질문에 대한 해답으로 상속시에 생성자를 모두 물려받는 것으로 정하면 되지 않을까 하는 생각이 제일 먼저 들 것이다. 그렇지만 이렇게 상속의 의미를 수정할 경우 기존에 이미 존재하던 수많은 코드들이 컴파일되지 않거나 컴파일은 되는데 예상치 못한 실행시 에러가 발생할 수 있다. 언어가 발전함에 있어 이런 급작스런 변화는 거의 불가능하다고 볼 수 있다. 기존 코드를 모두 깨뜨려버린다면 누구도 새로운 기능들을 채택하려 하지 않을 것이기 때문이다.

그렇다면 결국 생성자를 따로 상속받을 수 있는 방법을 고안해 내야 할 것이다. C++11 표준화 논의 중에 여러가지 방법들이 제안되었지만 최종적으로는 다음과 같이 using 선언을 이용하여  생성자를 물려받을 수 있다.

class B {
 int v_;

public:
 B() : B(0) {} // C++11의 위임생성자 기능 활용
 B(int v) : v_(v) {}
 int get();
 void set(int v);
};

class D : public B {
public:
 using B::B;
 void compute();
};

위와 같이 정의할 경우, D::D(int)가 암묵적으로 정의되며, 그 의미는 다음과 동일하다고 생각하면 된다.

class D : public B {
public:
 D(int v) : B(v) {}
 ...
};

따라서 다음과 같이 D를 사용할 수 있게 된다.

D d1; // 암묵적으로 정의됨
D d2(10); // 상속을 통해 암묵적으로 정의됨
D d3(d2); // 암묵적으로 정의됨

D::D(int)가 “암묵적으로” 정의된다는 것은 기본생성자인 D::D()과 복사생성자인 D::D(const D&)가 암묵적으로 정의된다는 의미이다. 왜냐하면 D::D(int)를 프로그래머가 명시적으로 정의한 것은 아니기 때문에 기본생성자 및 복사생성자 생성규칙에 따라 암묵적으로 정의된 것이다.

이렇게 상속생성자가 동일한 signature를 갖는 생성자를 반복해서 작성해야 하는 수고로움은 덜어 줬지만 잘못하면 다른 문제를 일으킬 수도 있다. 다음 예제를 보자.

class B {
 int v_;

public:
 B() : B(0) {} // C++11의 위임생성자 기능 활용
 B(int v) : v_(v) {}
 int get();
 void set(int v);
};

class D : public B {
 float v2_; // 초기화 필요
public:
 using B::B;
 void compute();
};

D d3(25);

언뜻 보기에는 문제가 없어 보일 수 있으나 컴파일러가 생성한 D::D(int)B::B(int)를 뜻하므로 d3.v2_는 초기화되지 않은 채로 사용될 것이다. 이쯤에서 우리는 다음과 같은 프로그래밍 경구를 기억할 수 밖에 없다.

“초기화되지 않은 변수를 사용하지 말라”

구식 방법으로 D::D(int)를 직접 작성하여 초기화할 수도 있지만, C++11에 새롭게 추가된 멤버초기화 기능을 이용하여 더 멋지게 해결할 수도 있다.

class D : public B {
 float v2_{0.0};        // 멤버초기화 기능 이용
public:
 using B::B;
 void compute();
};

D d3(25);                // v2_는 0.0으로 초기화 됨

참고문헌
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1890.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1898.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1583.pdf
http://www2.research.att.com/~bs/C++0xFAQ.html#inheriting
http://occamsrazr.net/tt/205

반응형
반응형



기존 typedef 로는 템플릿 인자는 template 을 허용하지 못했다




template<typename T>

typedef  std::vector<T> g1;            //이거 에러, 


에러명

/*

오류 C2823 형식 정의 템플릿이(가) 잘못되었습니다. Project1

*/




//그런데 using 을 다음처럼 사용해  템플릿 인수를 받아 다시 정의하는게 가능하다


template<typename T>

using ddd111 = std::vector<T>;





int main()

{


ddd111<int> d1;

d1.push_back(2);



..

}




이렇게 쓸대는 전역 변수로 타입을 선언해야 한다



참고 :


함수 포인터 또한 템플릿 인자를 받아 다시 정의 하는게 가능하다

http://blog.naver.com/bluerein_/220563677309






http://spikez.tistory.com/271


항목 9 : typedef 보다는 별칭(using) 을 선호하라.



STL 컨테이너들을 사용하는 것이 바람직하다. 이건 아마 c++을 사용하는 사람들은 동의 하리라 생각합니다.

std::unique_ptr의 사용 역시 바람직하다는 점에 대해서도 동의 할것 같구요.(저도 동의합니다.)


하지만, "std::unique_ptr<unordered_map<std::string, std::string>>" 을 여러번 타이핑하는 것은 하고 싶지 않죠( 120% 공감)


이럴때 typedef 를 사용합니다.

typedef std::unique_ptr<unordered_map<std::string, std::string>> UPtrMapSS;


C++98 에서 사용하던 방식이죠.


C++11에서는 별칭선언(alias declaration) 을 제공합니다.


using UPtrMapSS = std::unique_ptr<unordered_map<std::string, std::string>>;



이 둘의 차이가 있을까요?


그전에 한가지!!! (사실 이것 하나만 보더라도 흥미롭습니다.)


typedef void(*FP)(int , const std::string&);


using FP = void (*)(int, const std::string&);


둘 모두 같은 의미입니다. 함수 포인터를 type으로 선언한것인데요.

눈으로 보기에는 using으로 선언한 것이 더 편하고 명확해 보입니다.(물론 함수포인터 선언에 한해서만 봤을때죠.)



본격적으로 using을 선호해야 하는 이유에 대해서 다룹니다.


첫번째 typedef는 template 화 할 수 없습니다. using은 template화 할수 있습니다.


template<typename T>

using MyAllocList = std::list<T, MyAlloc<T>>;

MyAllocList<Widget> wg;




typedef를 사용할 경우,


template<typename T>

struct MyAllocList {

  typename std::list<T, MyAlloc<T>> type;

};


MyAllocList<Widget>::type wg;



이를 활용하는 template class를 만든다고 합시다.


template <typename T>

class Widget {

 private:

   typename MyAllocList<T>::type list;

};


C++의 규칙중에는 의존적인 형식(dependent type)의 이름 앞에 반드시 typename을 붙여야 합니다.


MyAllocList<T>::type은 템플릿 형식 매개변수 T에 의존적인 형식입니다.

따라서 typename을 붙여야 하며, 또 ::type역시 꼭 필요합니다.


보다시피 typedef를 사용하였을때 만들어야 하는 코드를 보면 "어떻게든 되게 만드는" 코드 처럼 보입니다.


using은 이런 점들을 보완해서 template을 좀더 자연스럽게 사용할 수 있도록 제공합니다.

template<typename T>

using MyAllocList = std::list<T, MyAlloc<T>>;

template <typename T>

class Widget{

 private:

  MyAllocList<T> list;

}


그리고 다음 사항까지도 고려해야합니다.

이 경우 MyAllocList<T>::type은 데이타 타입이 아니라 변수 type이 됩니다.

따라서 반드시 typename을 사용해야 합니다.


class Wine {...};


template <>

class MyAllocList<Wine> {

private:

  enum class WineType {Red, White, Rose};

  WinType type;

};

템플릿 메타 프로그래밍은 결국 현재까지 개발된 코드에서 문제 없는가도 중요하지만,

앞으로 개발될 새로운 코드에서도 적용 가능한가도 매우 중요하죠..


그때문에 이런 내용들까지도 고려를 해야합니다.




여기서 잠깐, 또 한가지 주의점이 있습니다.

C++11의 STL 에 type과 관련된 template method들이 있습니다.

std::remove_const<T>::type   // const T를 T로 변환

std::remove_reference<T>::type // T& T&&에서 &를 제거

std::add_lvalue_ref<T>::type //T를 T&로 변환


이 method들의 구현이 typedef로 구현되어 있기 때문에, ::type이라는 접미사를 붙여야 합니다.


이로 인해서 type이라는 이름을 template에서 사용할때는 유의해야합니다.


C++14에서는 이를 보완한 멋진 template method들이 있습니다.


std::remove_const<T>::type   //C++11

std::remove_const_t<T>      //C++14 에 추가

std::remove_reference<T>::type //C++11

std::remove_reference_t<T>     //C++14에 추가

std::add_lvalue_ref<T>::type //C++11

std::add_lvalue_ref_t<T>     //C++14에 추가


아, 그럼 C++11 사용자는 못쓰는건가????

책에 나온 내용을 보면, C++11 컴파일러를 사용하는 사람도 걱정을 할 필요가 없겠더군요.


지금까지 살펴본 using을 이용하면 아주 쉽게 처리할 수 있습니다.


template <class T>

using remove_const_t = std::remove_const<T>::type;


template <class T>

using remove_reference_t = std::remove_reference<T>::type;


template <class T>

using add_lvalue_ref_t = std::add_lvalue_ref<T>::type;




[참고] effective modern c++ : 항목 9



반응형

+ Recent posts