블로그 이미지
생각처럼

카테고리

전체보기 (209)
TOOL (1)
다이어리 (1)
Bit (200)
HELP? (0)
Total
Today
Yesterday

달력

« » 2025.1
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

공지사항

태그목록

최근에 올라온 글

C# windows form 의 경우 파라미터를 메인함수에서 받지 않고
Main Load 이벤트에서 

Environment.CommandLine() 함수를 사용하여 
처리가능하다 
커맨드라인의 첫번째는 프로그램 경로 두번째는 실행하는 파일의 경로 

이상!
Posted by 생각처럼
, |

c# 다국어 지원

Bit/C# / 2012. 2. 3. 16:55

[지디넷코리아]시간은 화살 같다는 말이 부쩍 실감나는 요즘입니다. 다들 연초에 세웠던 계획은 잘 지키고 있는지 모르겠네요. 다시 한번 숨을 돌리고 뒤를 돌아보며 앞으로 나갈 힘을 비축해야 할 때입니다.

이번에는 그동안 비주얼 스튜디오 6.0의 이런저런 테크닉을 이용해 어렵게 처리해야 했던 다국어 프로그래밍의 문제가 닷넷에서는 얼마나 쉽고 편하게 바뀌었는지 알아보도록 하겠습니다.

닷넷이 제공해 주는 여러 가지 이점
닷넷 프레임워크는 리소스와 관련된 여러 클래스와 도구들을 가지고 있습니다. 본격적으로 예제를 통해 다국어 프로그래밍을 연습해 보기 전에 우선 기본적인 지식을 쌓아보기로 할까요? 그 첫 번째로 다음에 소개하는 내용은 리소스 관련 클래스들입니다.

◆ 리소스 관련 클래스들
1. ResourceManager 클래스 : ResourceManager는 실행시 적절한 리소스에 접근할 수 있도록 해주는 클래스입니다. 지역화된 리소스가 존재하지 않을 경우에 대비해 언어 중립적인 리소스에 접근할 수 있도록 해주는 역할을 하며, CreateFileBasedResourceManager 라는 메쏘드를 이용하면 어셈블리 내부에 포함되어 있지 않은 리소스에 대한 접근도 가능하게 해줍니다. 
2. ResourceWriter 클래스 : ResourceWriter 클래스는 시스템의 기본 형식에 맞추어 리소스를 파일이나 스트림의 형태로 작성할 수 있게 해줍니다. AddResource라는 메쏘드를 이용해 이름-값의 짝의 형태로 관리할 수 있습니다.
3. ResourceReader 클래스 : ResourceReader 리소스 파일, 스트림 등을 읽어들일 수 있습니다. 
4. ResourceSet 클래스 : ResourceSet 클래스는 특정 문화에 맞춰 지역화된 모든 종류의 리소스를 저장할 수 있습니다. ResourceManager와는 달리 지역화된 리소스가 없을 경우의 대비책은 제공해 주지 않습니다. 
5. CultureInfo 클래스 : CultureInfo 클래스는 사용자의 주언어, 보조언어, 국가/지역, 문화 특성에 따른 사용자의 선호도에 따른 정보를 포함하고 있습니다. 이 클래스를 이용해 날짜 형식이나 시간 형식, 숫자 형식, 문자열의 정렬 등을 정의할 수 있습니다.
6. RegionInfo 클래스 : RegionInfo 클래스는 측정의 단위를 결정하고 지역 코드를 이름으로 변환하는 기준을 제공합니다.

또한 리소스 관련 도구들에는 어떤 것들이 있을까요?

◆ 리소스 관련 도구들
1. Resgen.exe(리소스 파일 생성 유틸리티) : 텍스트 파일과 .resx 파일을  .resources 파일로 변환시켜주는 유틸리티입니다. 또한 .resources 파일을 다시 .resx 파일로 변화시킬 수도 있습니다. 이 유틸리티에 사용되는 텍스트 파일은 ASCII, UTF-8, UTF-16 등의 형식이면 됩니다.
2. Al.exe(어셈블리 링커) : .resources 파일을 dll 파일로 변화시킬 수 있습니다.

이렇게만 말씀드리니 대체 무슨 말을 하는지 모르겠다구요? 앞에서 간략히 설명한 클래스들과 도구들은 실제 예제를 통해 그 사용법을 배워보기로 하겠습니다.

첫 번째 예제 - 다국어 폼 만들기
비주얼 스튜디오 닷넷을 시작해 LocalizationDemo1이라는 이름의 솔루션을 윈도우 응용 프로그램 형태로 만듭시다. 이후 Form1.cs를 <화면 1>과 같이 구성해 프로젝트에 새로운 폼 Form2.cs를 추가해 봅시다.

 
<화면 1> Form1의 구성   <화면 2> Form2 추가하기

‘닫기’ 버튼의 이름을 btnCloseForm으로 정하고, 클릭하면 폼이 닫히도록 다음의 코드를 추가해 둡시다.

this.Hide();

지역화를 지원할 수 있도록 Form2.cs의 속성 창에서 Localizable 속성을 True로 바꾸고, Language 특성을 기본 값에서 영어로 변경해 봅시다.

 
<화면 3> 영어를 지원할 수 있도록 속성창 변경하기   <화면 4> Language를 영어로 설정했을 경우의 Form2 구성

Lanuage를 영어로 바꾸는 순간, 리소스가 추가된다는 메시지 박스가 나타나서 이제 두 언어의 디자인 환경이 각각 다르게 관리된다는 사실을 알려주게 됩니다. 이제 다시 Form1의 디자인 환경으로 돌아가 봅시다. 프로그램 시작 버튼을 더블 클릭해서 다음의 코드를 추가합니다.

private void button1_Click(object sender, System.EventArgs e)
{
  if( this.radioButton1.Checked )
  {
//Get the Default installed culture
    System.Threading.Thread.CurrentThread.CurrentUICulture = 
         System.Globalization.CultureInfo.InstalledUICulture ; 
  }
  else if( this.radioButton2.Checked )
  {
//Get the English culture
    System.Threading.Thread.CurrentThread.CurrentUICulture = 
      new System.Globalization.CultureInfo("en") ;
  }
  Form2 f2 = new Form2();
  f2.Show();

}

첫 번째 라디오 버튼이 선택될 경우 실행되고 있는 환경의 기본 로케일을 따라 리소스를 선택해 폼을 로드하는 것이고, 두 번째 라디오 버튼이 선택되면 영어 환경에 맞춰진 리소스를 선택해 폼를 로드하는 코드입니다. 앞의 코드에서는 앞서 말씀드린 CultureInfo 클래스가 사용되었으며, 현재 실행 중인 쓰레드의 UI를 결정하기 위해 System.Threading.Thread.CurrentThread.CurrentUICulture라는 값을 이용하고 있습니다.

여기까지만 살펴보아도 닷넷이 기본적으로 제공해주는 지역화 도구가 상당히 편리해졌음을 알 수 있습니다. 예전 같으면 기본적인 리소스 편집기로는 사실 다국어 프로그래밍에 필요한 리소스를 편집하는 것이 불가능했습니다. 두 가지 언어의 리소스를 같이 입력하는 것 자체가 불가능했기 때문입니다. 하지만 닷넷은 폼의 Language 프로퍼티를 바꾸는 것만으로 간단하게 각각의 Culture에 대한 리소스를 디자인 환경에서 편집할 수 있는 강력함을 보여주고 있습니다. 또한 소스코드 자체도 유니코드로 관리되는 편리함도 제공합니다.

두 번째 예제 - 문자열 지역화하기
이제 두 번째 예제를 만들어 봅시다. 프로젝트의 이름을 LocalizationDemo2라고 하고, Form1을 <화면 5>과 같이 구성해 봅시다.
<화면 5> 예제 2의 Form1의 구성

디자인 환경에서 컨트롤을 추가할 때 자동으로 생성된 코드가 <리스트 1>처럼 나타납니다. 이중에서 윈도우 폼 디자이너에서 생성한 코드 부분을 열어 코드를 구경해 보면 여러분이 디자인 환경에서 한 작업이 어떻게 코드로 표시되었는지 확인할 수 있을 것입니다.

 <리스트 1> 자동으로 생성된 Form1.cs 소스의 일부

이제 프로젝트에 새 항목을 추가해 보겠습니다. 솔루션 탐색기의 프로젝트 명에서 오른쪽 마우스 버튼을 클릭해 추가 메뉴에서 새 항목 추가를 클릭해 봅시다. 이 중 ‘어셈블리 리소스 파일’을 선택해 새로 생성합니다(resource1.resx). 그리고 <화면 6>, <화면 7>처럼 resource1.resx에 값을 추가해 봅시다.

<화면 6> resource1.resx가 추가된 모습

<화면 7> resource1.resx에 값이 추가된 모습

프로젝트에 resource1.en-US.resx라는 이름의 어셈블리 리소스 파일을 추가해 <화면 8>과 같이 편집합니다.

<화면 8> resource1.en-US.resx 파일

이제 Form1.cs의 소스를 편집해 봅시다. 우선 다음의 네임스페이스들을 추가합니다.

using System.Resources;
using System.Globalization;
using System.Threading;

또한 컨트롤들이 선언된 아래에 다음의 코드를 추가합니다. ResourceManger 클래스를 이용해 닷넷에서 제공하는 기본적인 리소스 형식인 .resx를 로드할 수 있게 해주는 코드입니다.

private ResourceManager     m_ResourceManager = new ResourceManager("LocalizationDemo2.resource1", 
                System.Reflection.Assembly.GetExecutingAssembly());
private CultureInfo         m_EnglishCulture = new CultureInfo("en-US");
private CultureInfo         m_KoreanCulture = new CultureInfo("ko-KR"); 

다음 함수를 코드에 추가해 주고, Form1의 생성자에서 이를 호출합니다. UpdateUI 함수를 호출하면 resx 파일로부터 리소스를 읽어들여 각 컨트롤의 리소스를 변경하게 됩니다.

public Form1()
{
   //
   // 윈도우 폼 디자이너 지원에 필요합니다.
   //
   InitializeComponent();

   UpdateUI();

   //
   // TODO: InitializeComponent를 호출한 다음 생성자 코드를 추가합니다.
   //
}
        :
        :
private void UpdateUI()
{
   lblName.Text = m_ResourceManager.GetString("lblName");
   btnHello.Text = m_ResourceManager.GetString("btnHello");
   optKorean.Text = m_ResourceManager.GetString("optKorean");
   optEnglish.Text = m_ResourceManager.GetString("optEnglish");
}

마지막으로 다음의 이벤트 핸들러들을 코드에 추가해 라디오 버튼을 클릭했을 때 해당 언어의 인사말과 메뉴가 나오도록 수정합니다.

private void optKorean_CheckedChanged(object sender, System.EventArgs e)
{
   Thread.CurrentThread.CurrentUICulture = m_KoreanCulture;
   UpdateUI();
}

private void optEnglish_CheckedChanged(object sender, System.EventArgs e)
{
   Thread.CurrentThread.CurrentUICulture = m_EnglishCulture;
   UpdateUI();
}

private void btnHello_Click(object sender, System.EventArgs e)
{
   string message = String.Format(m_ResourceManager.GetString("greetingMessage"), txtName.Text);
   MessageBox.Show(this, message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}

완성된 프로그램을 실행하면 <화면 9>, <화면 10>처럼 한국어 옵션을 선택했을 때는 한국어 인사말이, 영어 옵션을 선택했을 때는 영어 인사말이 나옴을 확인할 수 있습니다.

 
<화면 9> 한국어 실행화면   <화면 10> 영어 실행화면

닷넷이 가진 다국어 프로그래밍의 힘
지금까지 살펴본 방법은 윈도우 환경 내에서 리소스를 편집하고 이를 불러오는 방법입니다. 이외에도 resgen.exe를 이용해  기존의 .resx 파일을 .resource 파일로 변경해 새로운 리소스 파일을 만들어낸 후 이를 Al.exe를 이용해 애플리케이션과 별개의 리소스 dll로 리소스를 관리하기도 합니다. 또한 텍스트 파일에 리소스를 저장하고 이를 불러오는 방법에 대비한 클래스들도 준비되어 있습니다.

앞서 말씀드린 것처럼 닷넷은 기존의 비주얼 스튜디오 6.0이 불완전하게 지원하던 다국어 프로그래밍을 설계 단계에서부터 완벽하게 지원할 수 있도록 되어 있습니다. 누군가 제게 다국어 프로그램을 하나 짜야한다고 말한다면 저는 주저없이 닷넷을 개발도구로 택할 것 같습니다. 그 편리함을 한 번 맛보고 나면 다시는 예전으로 돌아갈 수 없어서 말이죠.

지금까지 다섯번에 걸쳐 비주얼 베이직 6.0, 비주얼 C++ 6.0, 비주얼 스튜디오 닷넷을 이용해 다국어 프로그래밍을 하는 방법에 대해 간략하게 살펴보았습니다. 사실 연재에서 다뤄진 부분보다 훨씬 더 많은 것을 고려해야만 제대로 된 다국어 프로그램을 하나 만들어낼 수 있겠지만, 이번 글로 독자 여러분들께서 다국어 프로그래밍에 대한 기본적인 이해와 지식을 가져갔으면 하는 것이 필자의 작은 소망입니다. 그동안 읽어주셔서 감사합니다. 독자 여러분들 매일매일 행복한 날 되시고, 여러분의 프로그래밍 실력이 부쩍부쩍 늘어나길 기원해 봅니다. @
Posted by 생각처럼
, |

Resources and Localization

Bit/C# / 2012. 2. 3. 16:54
Resources and Localization
Ted Pattison

Code download available at: BasicInstincts05.exe (146 KB) 
Browse the Code Online
There are two ways you can utilize resources such as strings, images, and text-based files from your Microsoft® .NET Framework-based application. You can embed them directly in the app or you can load them from an external file. When you choose to load from an external source rather than from an embedding resource, you must distribute the files along with the assembly. You must also make sure that code inside the application can determine the correct path and load the resource files at run time. This approach causes problems if the .exe ever becomes separated from the files it depends upon.
Taking the embedded option and compiling the resources you need directly into the assemblies that use them makes distribution more reliable and less error prone. This month I will discuss the use of resources, how and why you might embed a resource, and the role of resource files in .NET.

Embedding a Resource
Let's start with a simple example to see how embedding is accomplished. Assume you would like to embed a graphic image named LitwareLogo.png into your Windows® Forms-based application. You begin by adding the file to the Visual Studio® project. Then, from within the property sheet for the file, you set the Build Action to Embedded Resource, as shown in Figure 1. By doing this, you have instructed Visual Studio to embed the file into the physical image of the output assembly .exe file.
Figure 1 Set Build Action 
Once you have embedded a file as a resource, you must learn how to access it at run time. Examine the following code fragment, which obtains a reference to the current assembly object and then calls the GetManifestResourceStream method to acquire stream-based access to the embedded resource file. This code assumes that you have imported the System.Reflection namespace and the System.IO namespace:
'*** get current Assembly object.
Dim asm As Assembly = Assembly.GetExecutingAssembly()
'*** load embedded resource into stream
Dim ResourceName As String = "LitwareSmartClient.LitwareLogo.png"
Dim str As Stream = asm.GetManifestResourceStream(ResourceName)
    '*** convert stream into image and load in    '*** picture box
    Dim img As Image = Image.FromStream(str)
    PictureBox1.Image = img
As you can see, an Assembly object exposes the GetManifestResourceStream method, which allows you to pass a string name that identifies the embedded resource. Note that the resource name is case-sensitive even when you are using a case-insensitive language like Visual Basic®. In the example, the code calls the Image.FromStream method to convert the stream containing the image file into an Image object that can be loaded into a PictureBox control.
In addition to embedding image files, it can be convenient to embed text-based files containing XML, SQL, or JavaScript. This can make your life a lot easier if you find it tedious to concatenate large string fragments of XML, SQL, or JavaScript using Visual Basic.
For example, let's say you have large XML documents, SQL statements, or JavaScript functions your application needs. You can maintain these as standalone .xml files, .sql files, and .js files within a Visual Studio project. With this you get the benefit of Visual Studio color coding and statement completion. You can also take advantage of Visual Studio schema-driven IntelliSense® for XML files. All that's required is that you embed these source files into the output assembly and access them using the technique you have already seen. For example, if you have embedded a SQL file and an XML file in a Windows Forms-based application, you can access them using code like that in Figure 2.
'*** get current Assembly object.
Dim asm As Assembly = Assembly.GetExecutingAssembly()

'*** load embedded SQL resources file
Dim SqlResourceName As String = "LitwareSmartClient.GetProducts.sql"
Dim strSQL As Stream = asm.GetManifestResourceStream(SqlResourceName)
Dim reader As New StreamReader(strSQL)
Dim sql As String = reader.ReadToEnd
reader.Close()

'*** load embedded XML resources file
Dim XmlResourceName As String = "LitwareSmartClient.Customers.xml"
Dim strXML As Stream = asm.GetManifestResourceStream(XmlResourceName)
Dim xmlDoc As New XmlDocument()
xmlDoc.Load(strXML)
strXML.Close()

Resource Files
The techniques you have just seen involve embedding resource files directly into an assembly and loading them using the GetManifestResourceStream method supplied by the Assembly class. But there is another alternative in .NET, resource files, which can make it even easier to handle resources in many scenarios. Plus, as you will see, Visual Studio 2005 provides some conveniences when it comes to working with resources and localizing apps.

Working with Resource Files
In .NET, resource files can be used to embed resources into assemblies. One of the key benefits of using resource files is that all the language and locale-specific elements in an application or class library DLL such as captions and user messages can be factored out of your application code. To do this you need to create a separate resource file for each spoken language that you need to support. The actual resource file is a text-based file containing XML with a .resx extension. Figure 3 shows a skimmed-down example of the XML data found inside a resource file.
<root>

 <data name="MainFormCaption">
   <value>Litware Customer Manager</value>
 </data>

 <data name="UserWelcome">
   <value>Good day</value>
 </data>

 <data name="ErrorMessage1">
   <value>Oh no, Something went wrong!</value>
 </data>

</root>
While the XML fragment in the figure isn't a complete resource file, it gives you a general idea of what's inside one. You can compile a resource file into a binary image using a .NET-based utility called the resource file generator (Resgen.exe). Compiled resource files typically have a .resources extension. For example, a developer at the company named Litware can create a resource file named LitwareStrings.resx and compile it into a binary image named LitwareStrings.resources by executing the following command within a batch file or from the Visual Studio 2005 Command Prompt:
RESGEN.EXE LitwareStrings.resx LitwareStrings.resources
After you compile a text-based .resx file into a binary .resource file, it is still not yet ready to use. Instead, you must further compile this binary image into a .NET assembly before you can use it from an application. This can be accomplished using another .NET tool called the Assembly Linker (Al.exe). For example, to compile LitwareStrings.resources into its own assembly DLL, you can run the following command-line instruction from a batch file or from the Visual Studio 2005 command prompt:
AL.EXE /t:library 
 /out:LitwareStrings.resources.dll 
 /link:LitwareStrings.resources
 
Once you have compiled a resource file into a .NET assembly, you can access the resources inside using the ResourceManager class that is defined in the System.Resources namespace. The following shows a simple example of code that accesses a string resource using the ResourceManager:
Dim asm As Assembly = Assembly.Load("LitwareStrings.resources")
Dim rm As New System.Resources.ResourceManager("LitwareStrings", asm)
Dim caption As String = rm.GetString("MainFormCaption")
Resgen.exe can also be used to generate a strongly typed resource class that exposes properties providing easy access to the resource inside. For example, to a generate a strongly typed resource class in Visual Basic, you can add the /str parameter and a value of "vb" to the command line when calling Resgen.exe:
RESGEN.EXE LitwareStrings.resx LitwareStrings.resources /str:vb 
This command-line instruction generates a Visual Basic source file named LitwareStrings.vb. This source file contains a class named LitwareStrings. Inside the class, there is code that uses the ResourceManager to implement strongly typed properties that look like this:
Shared ReadOnly Property MainFormCaption() As String
  Get
    Return ResourceManager.GetString("MainFormCaption", resourceCulture)
  End Get
End Property 
I have just quickly stepped through a high-level explanation of how resource files are compiled into assemblies and how they can be accessed using the ResourceManager class and strongly typed resource classes.This should give you a better idea of how the individual pieces fit together.
I don't want to spend any more time here on the low-level details of resource files because you will not be required to deal with them when you begin localizing applications and class library DLLs. That's because Visual Studio 2005 and Visual Basic supply many valuable conveniences behind the scenes. However, keep in mind that you might have to work directly with Resgen.exe, Al.exe, and some of the other .NET-based utilities and classes when you are localizing large-scale development projects.

Resource Files in Visual Studio 2005
Now I am going to focus on using resource files in a Windows Forms-based application. Most of the concepts I explain will apply to using resource files in a class library DLL as well. Visual Studio 2005 makes it easy to work with resource files by supplying a visual editor. You can create a new resource file using the Add New Item command and choosing Resources file, as shown in Figure 4.
Figure 4 New Item Template for Adding Resource Files 
Once you have added a resource file to a project, there's no need to work directly with the XML format required inside a .resx file. Instead, Visual Studio supplies the friendly visual resource designer that is shown in Figure 5. This resource file designer makes it easy to add and maintain strings as well as other types of file-based resources such as graphics and XML documents.
Figure 5 Visual Studio Resource Editor 
When you compile a project that contains a resource file, Visual Studio compiles this .resx file into a .resources file and then links it inside the physical image of the resulting output assembly. That means that all the details involved in compiling the resource file and embedding it into the image of the target assembly are handled for you by Visual Studio.
Visual Studio also builds in a strongly typed resource class and exposes it in Visual Basic projects using the My namespace features introduced in Visual Basic 2005. That means you get the benefit of having the .NET ResourceManager class loading your resources, yet you never have to program directly against this class. For example, if you want to access resource strings you have added to LitwareStrings.resx, you can simply write the following code:
Sub Main_Load(sender As Object, e As EventArgs) 
  Handles MyBase.Load
  Me.Text = _
    My.Resources.LitwareStrings.MainFormCaption
  Me.lblUserWelcome.Text = _
    My.Resources.LitwareStrings.UserWelcome
End Sub

The Project-Level Resource File
While you can explicitly add one or more resource files to a Visual Studio project, that's often unnecessary because Visual Studio automatically includes a project-level resource file each time you create a new project. The project-level resource file can be accessed through the Project Properties dialog in the Visual Studio editor.
When you want to access resources such as strings from the project-level resource file, you can access them directly from within the My.Resources class:
Private Sub LoadResources()
  '*** load project-level resources
  Me.Text = My.Resources.MainFormCaption
  Me.lblWelcomeMessage.Text = My.Resources.UserWelcome
End Sub
As you can see, accessing strings from a resource file using a strongly typed resource class is pretty easy. You can take things a step further and get the same sort of strongly typed access to file-based resources when you have added graphics images and files containing things like XML, SQL, and JavaScript to a resource file. For example, assume you have added a graphics file named LitwareLogo.png and an XML file named Customers.xml to your project-level resource file. These resources will be automatically embedded into the project's output assembly and you can access them in a strongly typed fashion using the following code:
Me.picLogo.Image = My.Resources.LitwareLogo

Dim xmlDoc As New Xml.XmlDocument
xmlDoc.LoadXml(My.Resources.Customers)
You can observe that the strongly typed resource class automatically converts a.png file into an Image object that can be directly loaded into a PictureBox. The strongly typed resource class also converts the embedded XML file into a string that can be easily loaded into an XmlDocument object.

Culture Settings and Localization
It's a common requirement for software projects to be localized so they can be used by people who speak different languages. For example, imagine you are developing the Litware Customer Manager application with Visual Basic and Visual Studio 2005 and you are required to write localized versions of the application for users who speak English as well as users who speak French. Fortunately, the Microsoft .NET Framework and Visual Studio have many features geared toward localizing applications and class library DLLs.
When you first start designing and writing .NET-based software projects that need to support localization, you must quickly become familiar with the CultureInfo class defined inside the System.Globalization namespace. A CultureInfo object tracks a culture name that identifies a spoken language.
The culture name for English is "en" and the culture name for French is "fr". The culture name of a CultureInfo object can also carry additional information that identifies a particular region in the world such as "en-US" for US English, "en-GB" for British English, and "fr-BE" for Belgian French. Here's an example that creates and initializes CultureInfo objects with valid culture names:
Dim culture1 As CultureInfo = New CultureInfo("en-US")
Dim culture2 As CultureInfo = New CultureInfo("en-GB")
Dim culture3 As CultureInfo = New CultureInfo("fr")
Dim culture4 As CultureInfo = New CultureInfo("fr-BE")
There are actually two CultureInfo objects associated with the current thread that require your attention. The first CultureInfo object listed represents the current culture while the second CultureInfo object represents the current UI culture. You can determine the culture names for each of these two CultureInfo objects with the following code:
'*** determine current culture and current UI culture
Dim t As Thread = Thread.CurrentThread
Dim currentCulture As CultureInfo = t.CurrentCulture
Dim currentUICulture As CultureInfo = t.CurrentUICulture

'*** display cultures in console
Console.WriteLine("Current Culture: " & currentCulture.Name)
Console.WriteLine("Current UI Culture: " & currentUICulture.Name)
The first CultureInfo object known as the CurrentCulture is not used to localize strings in applications. Instead, it affects how the .NET Framework formats dates, numbers, and currency. For example, if you modify the CurrentCulture object back and forth between en-US and en-GB, it can lead to strange side effects such as a single currency value switching back and forth between US dollars ($100.00) and British Pounds ($100.00). As you can see, switching the currency formatting on a currency value can lead to incorrect results. For this reason, it's a common practice to keep the CurrentCulture static even when localizing your application for use with different languages.
If you determine that you do need to programmatically change the CurrentCulture, you should remember that you must use a culture name that includes a regional identifier. You can use a culture name of en-US, en-GB, or fr-BE. However, you will receive run-time errors if you try to change the CurrentCulture so that it has a culture name of en or fr because there is no regional information and formatting requirements become too ambiguous.
The second CultureInfo object known as the CurrentUICulture is far more important to the discussion of .NET-based application localization. Modifications to the CurrentUICulture object associated with the current thread influence how the .NET Framework and the ResourceManager class load assemblies that contain embedded resources. In particular, it can have the effect of loading the set of resources that have been localized to the language preferred by the current user.
To begin localization, you make multiple copies of resource files-one copy of each resource file for each language you want to support. For example, start by taking the project-wide resource file named Resources.resx and making a copy. You can do this with a simple copy-and-paste operation right inside the Visual Studio Solution Explorer.
Once you have copied a resource file such as Resources.resx, rename the copied resource file by adding the culture name just before the .resx extension, as shown in Figure 6. For example, you should have resource files named Resources.fr.resx for generic French localized strings and another resource file named Resources.fr-BE.resx for French strings localized specifically for Belgium.
Figure 6 Separate Resource Files for Each Language 

Satellite Assemblies
When you compile the project with localized resource files like the one that is shown in Figure 6, Visual Studio does not compile all the resources into a single output assembly. Instead, it compiles each of these localized resource files into its own separate assembly. Each of these localized assemblies contains only resources and no code. This type of localized, resource-only assembly is known as a satellite assembly.
Each satellite assembly is associated with a master assembly known as the neutral assembly. The neutral assembly contains all the code and it loads whatever satellite assembly is necessary to get the localized resources required by the current user. In my example, LitwareSmartClient.exe is the neutral assembly which contains all the application code. Then there are several satellite assemblies associated with LitwareSmartClient.exe. Each of these has the same file name, LitwareSmartClient.resources.dll.
When satellite assemblies are deployed along with the neutral assembly in the AppBase directory, they must be deployed according to the rules of the .NET assembly loader. In particular,each satellite assembly must be deployed in a directory named after its localized culture name. For example, the AppBase directory that contains LitwareSmartClient.exe should contain a subdirectory named fr-BE which holds the satellite assembly localized for Belgian French named LitwareSmartClient.resources.dll. As long as these rules are followed, the .NET Framework assembly loader along with the assistance of the ResourceManager class will load the correct set of resources when required.
Fortunately, Visual Studio knows how to name the satellite assemblies correctly and how to deploy them in the correct directory structure expected by the .NET assembly loader. To gain a better understanding of how all of the various pieces fit together, you can simply compile your project and then examine the resulting structure of the AppBase directory and the subdirectories inside that hold the satellite assemblies.

Loading Localized Resources
Once you have created and edited all the required localized resource files and compiled your project, it's time to concentrate on how you are going to make your application load the correct set of localized strings that are preferred by the current user. One way you can accomplish this is to obtain a reference to the current thread and assign a new created CultureInfo object to the CurrentUICulture property. If you are writing a Windows Forms-based application in Visual Basic, you can also use the following code:
My.Application.ChangeUICulture("fr-BE")
In the sample app that accompanies this column, I added support for the users to select their preferred language and to have the application track user language preferences when the application is shut down and restarted. While it is possible to maintain these sorts of user preferences using registry keys, Visual Studio 2005 makes it possible to avoid using the registry by adding an application setting that is tracked on a user-by-user basis. The sample app tracks a user-scoped application setting named UserLanguagePreference for this purpose. The application also contains an application startup event (seeFigure 7).
'*** code in ApplicationEvents.vb
Namespace My
 Partial Friend Class MyApplication
   Private Sub MyApplication_Startup(ByVal sender As Object, _
       ByVal e As StartupEventArgs) Handles Me.Startup

     '*** initialize application by setting preferred language
     Dim lang As String = My.Settings.UserLanguagePreference
     My.Application.ChangeUICulture(lang)

   End Sub
 End Class
End Namespace
The sample application also provides the user with a group of radio buttons as a means to switch from one language to another. Figure 8 shows a fragment of code from the event handler that responds to a user's request to change languages.
'*** retrieve user's language preference
Dim lang As String = CType(sender, Control).Tag

'*** save user setting
My.Settings.UserLanguagePreference = lang
My.Settings.Save()

'*** change application's UI culture
My.Application.ChangeUICulture(My.Settings.UserLanguagePreference)

'*** call custom method to reload localized strings
LoadResources()
You have now seen all the fundamental code that allows the user to switch languages. The .NET Framework responds to the call to My.Application.ChangeUICulture by loading in the correct satellite assembly the next time the ResourceManager retrieves strings from the project-level resources. After the call to ChangeUICulture, the application can then requery the application-level resource strings and load them into controls on the form with the exact same code you saw earlier inside the custom LoadResources method:
Me.Text = My.Resources.MainFormCaption
Me.lblWelcomeMessage.Text = My.Resources.UserWelcome
Note that the .NET assembly loader will first attempt to find an exact match with both language and region between the requested culture name and the culture name of an available satellite assembly. If the .NET assembly loader cannot find an exact match, it will then look for an available satellite assembly with a matching language. For example, if the requested language is fr-CA for Canadian French, the .NET Framework would first look for a satellite assembly with that language. If it cannot locate a satellite assembly with fr-CA, it then looks for a satellite assembly with a culture name of fr. If the .NET Framework cannot locate a satellite assembly with a culture name of fr, it then resorts to using the resources found within the neutral assembly, which has a set of default culture resources embedded inside. As you just saw, the .NET Framework can always fall back on the default culture resources from the neutral assembly if it cannot find a more specific satellite assembly.
When you compile the neutral assembly, you can mark it with a special attribute to inform the .NET Framework that the default culture resources are sufficient for those users who require a specific language. For example, you can add an assembly-level attribute to the AssemblyInfo.vb file of a Windows Forms-based application project, as shown in the following line of code:
<Assembly: System.Resources.NeutralResourcesLanguage("en")>
As it is used here, the NeutralResourcesLanguage attribute informs the .NET assembly loader that it can use the default culture resources whenever the current user has requested that the application be localized for English.

Localizing Form and Control Settings
You have just seen how to localize string resources on a project-wide basis. This technique involves copying and maintaining localized resource files. Visual Studio 2005 provides some extra assistance when you need to localize strings specific to a form and the controls it contains.
Each form has a Localizable property that can be set to either true or false. If you set this property to true, as shown in Figure 9, Visual Studio 2005 will create and maintain a set of localized resource files for you behind the scenes.
When you set the Localizable property to true, the initial Language setting is default. As you add property values into the property sheet for the form and its controls, Visual Studio maintains them in a resource file behind the scenes that is compiled into the neutral assembly. When you change the Language property of the form to a specific language, such as "French (Belgium)," Visual Studio then creates a new localized resource file that will be compiled into a satellite assembly. Behind the scenes, things work exactly as they do with project-wide resources. It's just that Visual Studio eliminates your need to work directly with resource files and allows you to work with a standard property sheet as you add property values for things such as control Text properties.
Figure 9 Localizable Property 
Visual Studio is required to add some extra code into the form behind the scenes to support form localization. In particular, Visual Studio adds code to load the correct localized resources and assign their values to form and control properties. Instead of using the ResourceManager, the code generated by Visual Studio 2005 uses a more specialized class that derives from ResourceManager named ComponentResourceManager that is defined in the System.ComponentModel namespace.
When a localized form loads, everything required to load the localized resources is done for you by the code that is generated by Visual Studio. In particular, Visual Studio supplies the code to create an instance of the ComponentResourceManager, which loads the proper set of resources and assigns all the necessary control values.
However, if a form is already loaded and the user switches languages, you must supply some additional code to refresh the form with the resources of the requested language. The following shows a sample of code that uses the ComponentResourceManager to accomplish this goal:
Dim crm As ComponentResourceManager
crm = New ComponentResourceManager(GetType(Main))
crm.ApplyResources(cmdAddCustomer, cmdAddCustomer.Name)
crm.ApplyResources(mnuFile, mnuFile.Name)
crm.ApplyResources(mnuFileAddCustomer, mnuFileAddCustomer.Name)
As you can see, you can create and initialize an instance of the ComponentResourceManager by passing type information about the form, which in this case is named Main.
The completed sample application, which demonstrates all the localization techniques discussed in this column, is shown in Figure 10. The application now supports US English, British English, and Belgian French. Also note that since there is a satellite assembly localized to fr without any specific region, the application also supports a generic form of French for users around the world who speak French.
Figure 10 Supporting Localized Versions 
If you want to add support for additional languages in the future, it's not very complicated. It's simply a matter of creating and maintaining additional resource files. In fact, you can add support for new languages without ever having to recompile the neutral assembly that contains all the application code. This is one of the most valuable features of the .NET Framework strategy for localizing applications and class library DLLs.

Conclusion
This month's column covered the fundamentals of resources and localization in the .NET Framework by working through how to localize a simple Windows Forms-based application. In my next Basic Instincts column, I will build upon what I covered this month and move on to a discussion of resource and localization in ASP.NET 2.0, which has some valuable and unique features for utilizing resources and localizing applications.


Send you questions and comments for Ted to  instinct@microsoft.com.

Posted by 생각처럼
, |
vba로 작성된 코드를 c/c++이나 vb로 바꾸려다보면 제일 먼저 걸리는 문제가 엑셀과 관련된 부분을 바꿔야하는 것이다. 특히 worksheetfunction을 사용하는 경우 더욱 그러하다. 별 고민없이 가져다 사용한 함수를 따로 만들어야 한다. 이럴때 엑셀의 편리함을 절실히 느끼게 되고 심한 경우엔 그냥 vba로 주저앉게 된다. vba로 만든 ADF(Augmented Dickey Fuller test)를 vb로 바꾸려니 통계함수가 걸리는 것이다. 

NORMSDIST()함수는 표준 정규 누적 분포 함수의 확률값을 구한다. 이 분포의 평균은 0이고 표준 편차는 1이다. NORMDIST()함수는 지정한 평균과 표준편차에 따라 정규분포값을 구한다. 따라서 NORMSDIST()함수는 NORMDIST()함수의 특별한 경우라고 볼 수 있다. 즉 NORMSDIST(x)=NORMDIST(x,0,1,TRUE)와 같다.

다음은 NORMSDIST()함수의 vb버전이다.
'// The cumulative normal distribution function
Public Function CND(X As Double) As Double
   Const PI = 3.14159265358979
   Dim L As Double
   Dim K As Double
   
   Const a1 = 0.31938153
   Const a2 = -0.356563782
   Const a3 = 1.781477937
   Const a4 = -1.821255978
   Const a5 = 1.330274429
   
   L = Abs(X)
   K = 1 / (1 + 0.2316419 * L)
   CND = 1 - 1 / Sqr(2 * PI) * Exp(-L ^ 2 / 2) _
       * (a1 * K + a2 * K ^ 2 + a3 * K ^ 3 + a4 * K ^ 4 + a5 * K ^ 5)
   If X < 0 Then
       CND = 1 - CND
   End If
End Function
Posted by 생각처럼
, |

/*Lognormdist = NORMSDIST((LN(x) – mu)/sigma)  eg:- Lognormdist(0.367879441,3,2) will give  0.022750062 with this function and in excel it will give 0.022750132*/

/* Note: Doouble quotes for “en-US” and “F” may not be properly shown while pasting this code.you need to manaully remove the double quotes and add it again*/

   public double Lognormdist( double x, double zeta, double sigma)

  {
  /*Gets a NumberFormatInfo associated with the en-US culture.*/

  System.Globalization.NumberFormatInfo nfi =new System.Globalization.CultureInfo( “en-US”, false ).NumberFormat;nfi.NumberDecimalDigits = 9;

  double u = (Math.Log(x) – zeta)/sigma; double p = this.NormalDistribution(u);

  return Convert.ToDouble(p.ToString(“F”, nfi) );
  }
  private double NormalDistribution(double X)
  {

  /* Gets a NumberFormatInfo associated with the en-US culture.*/
  System.Globalization.NumberFormatInfo nfi =new System.Globalization.CultureInfo( “en-US”, false ).NumberFormat;nfi.NumberDecimalDigits = 9;

  double L = 0.0; double K = 0.0; double dCND = 0.0; const double a1 = 0.31938153; const double a2 = -0.356563782; const double a3 = 1.781477937; const double a4 = -1.821255978; const double a5 = 1.330274429;L = Math.Abs(X);K = 1.0 / (1.0 + 0.2316419 * L);dCND = 1.0 – 1.0 / Math.Sqrt(2 * Convert.ToDouble(Math.PI.ToString())) * Math.Exp(-L * L / 2.0) * (a1 * K + a2 * K * K + a3 * Math.Pow(K, 3.0) + a4 * Math.Pow(K, 4.0) + a5 * Math.Pow (K, 5.0));

  if (X < 0){double ff = Convert.ToDouble(dCND.ToString( “F”, nfi )); return 1.0 – dCND;}

  else{ return dCND;}
  }

Posted by 생각처럼
, |
/// <summary>
        /// beta函数
        /// </summary>
        public static double Beta(double a, double b)
        {
            double result = 0.0;

            if (a <= 0 || b <= 0)
            {
                //报错!a,b必须同时大于零;
            }
            else
            {
                result = Math.Exp((gammaln(a) + gammaln(b) - gammaln(a + b)));
            }
            return result;
        }

        /// <summary>
        /// gammaln函数
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static double gammaln(double x)
        {
            double res = 0.0;
            double d1 = -5.772156649015328605195174e-1;

            double[,] p1 = {{4.945235359296727046734888e0},{ 2.018112620856775083915565e2},
                           {2.290838373831346393026739e3},{ 1.131967205903380828685045e4},
                           {2.855724635671635335736389e4},{ 3.848496228443793359990269e4},
                           {2.637748787624195437963534e4},{ 7.225813979700288197698961e3}};

            double[,] q1 = {{6.748212550303777196073036e1},{ 1.113332393857199323513008e3}, 
                           {7.738757056935398733233834e3},{ 2.763987074403340708898585e4},
                           {5.499310206226157329794414e4},{ 6.161122180066002127833352e4}, 
                           {3.635127591501940507276287e4},{ 8.785536302431013170870835e3}};

            double d2 = 4.227843350984671393993777e-1;

            double[,] p2 = {{4.974607845568932035012064e0},{ 5.424138599891070494101986e2},
                           {1.550693864978364947665077e4},{ 1.847932904445632425417223e5},
                           {1.088204769468828767498470e6},{ 3.338152967987029735917223e6}, 
                           {5.106661678927352456275255e6},{ 3.074109054850539556250927e6}};

            double[,] q2 = {{1.830328399370592604055942e2},{ 7.765049321445005871323047e3},
                           {1.331903827966074194402448e5},{ 1.136705821321969608938755e6},
                           {5.267964117437946917577538e6},{ 1.346701454311101692290052e7},
                           {1.782736530353274213975932e7},{ 9.533095591844353613395747e6}};

            double d4 = 1.791759469228055000094023e0;

            double[,] p4 = {{1.474502166059939948905062e4},{ 2.426813369486704502836312e6}, 
                           {1.214755574045093227939592e8},{ 2.663432449630976949898078e9},
                           {2.940378956634553899906876e10},{ 1.702665737765398868392998e11},
                           {4.926125793377430887588120e11},{5.606251856223951465078242e11}};

            double[,] q4 = {{2.690530175870899333379843e3},{ 6.393885654300092398984238e5}, 
                           {4.135599930241388052042842e7},{ 1.120872109616147941376570e9},
                           {1.488613728678813811542398e10},{1.016803586272438228077304e11},
                           {3.417476345507377132798597e11},{ 4.463158187419713286462081e11}};

            double[,] c = {{-1.910444077728e-03},{ 8.4171387781295e-04}, 
                          {-5.952379913043012e-04},{ 7.93650793500350248e-04}, 
                          {-2.777777777777681622553e-03},{ 8.333333333333333331554247e-02}, 
                          { 5.7083835261e-03}};

            double eps = 2.2204e-016;
            if (x <= 0)
            {
                //报错!
            }
            else
            {
                double xden = 0.0;
                double xnum = 0.0;

                res = x;
                if (x > 0 && x <= eps)
                {
                    res = -Math.Log(x);
                }
                else if ((x > eps) && (x <= 0.5))
                {
                    double y = x;
                    xden = 1;
                    xnum = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        xnum = xnum * y + p1[i, 0];
                        xden = xden * y + q1[i, 0];
                    }
                    res = -Math.Log(y) + (y * (d1 + y * (xnum / xden)));
                }
                else if ((x > 0.5) && (x <= 0.6796875))
                {
                    double xm1 = (x - 0.5) - 0.5;
                    xden = 1;
                    xnum = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        xnum = xnum * xm1 + p2[i, 0];
                        xden = xden * xm1 + q2[i, 0];
                    }
                    res = -Math.Log(x) + xm1 * (d2 + xm1 * (xnum / xden));
                }
                else if ((x > 0.6796875) && (x <= 1.5))
                {
                    double xm1 = (x - 0.5) - 0.5;
                    xden = 1;
                    xnum = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        xnum = xnum * xm1 + p1[i, 0];
                        xden = xden * xm1 + q1[i, 0];
                    }
                    res = xm1 * (d1 + xm1 * (xnum / xden));
                }
                else if ((x > 1.5) && (x <= 4))
                {
                    double xm2 = x - 2;
                    xden = 1;
                    xnum = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        xnum = xnum * xm2 + p2[i, 0];
                        xden = xden * xm2 + q2[i, 0];
                    }
                    res = xm2 * (d2 + xm2 * (xnum / xden));
                }
                else if ((x > 4) && (x <= 12))
                {
                    double xm4 = x - 4;
                    xden = -1;
                    xnum = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        xnum = xnum * xm4 + p4[i, 0];
                        xden = xden * xm4 + q4[i, 0];
                    }
                    res = d4 + xm4 * (xnum / xden);

                }
                else if (x > 12)
                {
                    double y = x;
                    double r = c[6, 0];// 等于:double r = repmat(c[6, 0], 1)[0,0];
                    double ysq = y * y;
                    for (int i = 0; i < 6; i++)
                    {
                        r = r / ysq + c[i, 0];
                    }
                    r = r / y;
                    double corr = Math.Log(y);
                    double spi = 0.9189385332046727417803297;
                    res = r + spi - 0.5 * corr + y * (corr - 1);
                }
            }

            return res;
        }
Posted by 생각처럼
, |

C언어 최적화

Bit/C&C++ / 2012. 2. 3. 16:49

  • 원문 : http://www.codeproject.com/cpp/C___Code_Optimization.asp
  • 출처 : DC인사이드 프로그래밍 갤러리
  • 1 소개

    얼마전에 모바일기기에서 일정수준의 품질을 유지하면서 실행되는 JPEG라이브러리를 만드는 프로젝트를 진행한적이 있었다. 이 프로젝트를 진행하면서, 여러가지 방법으로 프로그램을 더 빨리 만들 수 있다는 사실을 경험적으로 알게 되었다. 이 문서는 C로된 코드를 속도와 메모리 양측모두에서 최적화하기 위한 경험적인 정보들을 포함하고 있다. 

    물론 여러분은 C 코드를 최적화 하는 방법에 대한 참고문서를 어렵지 않게 획득할 수 있을 것이다. 그러나 대부분의 문서가 팁수준에서 문제에 접근할 뿐으로, 컴파일러나 기계어수준에서 어떻게 프로그래밍을 해야 하는지에 대한 정보는 담고 있지 않다.

    보통 프로그램의 속도를 높이게 되면 코드의 크기가 늘어나게 된다. 코드의 크기가 늘어나면 프로그램이 복잡해지고, 읽고 이해하기 어려워진다. 메모리 자원이 넉넉한 개인PC혹은 서버 컴퓨터라면 문제가 되지 않겠지만 PDA와 같은 제한된 메모리 자원을 가진 기기일 경우 심각한 문제가 될 수 있다. 1%의 속도향상을 위해서 코드의 크기가 10%만큼 늘어난다면 분명 문제가 될 것이다. 이런 이유로 속도와 코드크기 모두에 대한 최적화를 수행하기로 결정을 했다. 

    2 선언

    내가 진행하는 프로젝트가 ARM 플랫폼에서 진행된 관계로, ARM 최적화와 관련된 팁들이 필요했었다. 나는 인터넷을 통해서 ARM 최적화와 관련된 많은 문서를 검색하고 이중 유용한 것들 중심으로 수집해서 테스트를 했었다. 그러나 대부분의 문서들이 나에게는 도움이 되지 않았음을 고백한다. 이러한 실수를 줄이기 위해서 유용하고 효과적인 몇개의 팁만을 모으기로 결정했다.

    3 어디에 필요한가

    토론의 주제를 명확히 하고 넘어가자. 컴퓨터 프로그램을 최적화하기 위한 가장 중요한 것은 프로그램을 이루는 각각의 모듈중 어느 부분이 느리게 작동하거나, 큰 메모리를 소비하는지를 찾아내는 것이다. 이들 각각의 부분을 최적화하면 프로그램이 전체적으로 빨라질 것이기 때문이다. 이러한 모듈단위의 최적화는 최적화를 위한 부분을 비교적 쉽게 찾고, 쉽게 해결할 수 있다는 장점을 가진다.

    The optimizations should be done on those parts of the program that are run the most, especially those methods which are called repeatedly by various inner loops that the program can have.

    일반적으로 경험이 풍부한 프로그래머들은 아주 쉽게 프로그램이 요구하는 최적화될 필요가 있는 핵심을 쉽게 찾아낼 수 있을 것이다. 가장 좋은 최적화 방법은 경험많은 프로그래머를 고용하는 것이다. 그러나 경험많은 프로그래머는 매우 드물며, 경험이 많다고 해도 더 좋은 결과를 위해서는 최적화를 위한 좋은 툴을 사용할 필요가 있다. Visual C++ 과 같은 통합 개발환경은 함수단위로 프로그램의 소비시간을 측정할 수 있는 profiler를 제공한다. 리눅스의 경우에는 gprof와 같은 profiler를 사용할 수 있다. 혹은 Intel Vtune와 같은 프로그램을 사용할 수 있는데, 이들 프로그램을 사용하면 프로그램의 어느부분이 가장 많은 시간을 소비하는지를 확인할 수 있다. 개인적인 경험으로 루프 혹은 third party 라이브러리 메서드를 호출하는 영역이 프로그램을 느리게 하는 경우가 많았다. 

    3.1 정말 빨라지는 가 ?

    아래의 최적화 기법을 적용한다고 해서, 항상 빨라진다는 걸 보장할 수는 없다. 컴파일러의 버전과 종류, 만들고자 하는 애플리케이션의 특징에 따라서 결과가 달라질 수 있기 때문이다. 만약 임베디드기기에 올라가는 애플리케이션이 아닌, 고수준의 애플리케이션의 개발이 목적이라면 아래의 최적화 기법은 그다지 소용이 없을 것이다. 고수준 애플리케이션이라면, 미세한 성능최적화를 위한 노력하는 것 보다는 주요 데이터처리 알고리즘과 가독성에 신경을 쓰는게 더 나은 결과를 보여줄 것이다.

    4 데이터 연산

    4.1 정수

    우리가 사용할 값이 음수가 아니라면 int 형대신에 unsigned int형을 사용해야 한다. 어떤 프로세스들은 unsigned integer의 연산이 signed 연산보다 매우 빠르다. 또한 나누기/나눗셈 작업의 경우에도 음수가 필요 없다면 unsigned 를 명시해주는게 좋다. 

    루프에 사용될 변수라고 한다면, 다음과 같이 깔끔하고 효율적으로 선언할 수 있을 것이다.
    register unsigned int variable_name; 
     

    기억해야할 또다른 점은 floating point 연산은 매우 느리다라는 점이다. floating point 데이터 타입은 자바와 함께 하는 컴퓨터과학문서를 참고하기 바란다. 척 봐도 floating point 숫자는 다루기가 꽤나 복잡하다는 것을 알 수 있을 것이다. 만약 여러분이 소숫점 2자리까지의 정확도를 유지하는 회계프로그램을 만든다면, 모든 값에 x100을해서 int 형으로 바꾼다음 연산을 하도록 한다. 가능하면 외부의 수학라이브러리를 사용하지 않도록 한다. FPUs와 같은 라이브러리는 매우 느리다.

    4.2 나눗셈 그리고 나머지

    표준적인 프로세서에서의 분모와 분자의 32bit 나눗셈은 20~140의 실행 사이클을 가지고 있다. 나눗셈을 이용하면 다음과 같은 시간이 소비된다. 
    Time (numerator / denominator) = C0 + C1* log2 (numerator / denominator) 
    = C0 + C1 * (log2 (numerator) - log2 (denominator)). 
     
    널리 쓰이는 버젼은 약 20+4.3N의 사이클을 보여준다. ARM 뿐만 아니라 프로세서를 막론하고 이런 연산은 피하는게 바람직하다. 나눗셈연산은 가능하다면 곱셈으로 대체해서 사용하기 바란다. 

    예를들어 (a/b) > c 는 b * c가 integer 범위안이라는 것을 안다면 a > (c * b)로 다시 쓰일 수 있다. 

    4.3 Combining division and remainder

    나눗셈 (x/y) 그리고 나머지(x%y)둘다 종종 필요한 케이스이다
    그러한 케이스에 비추어보아 나눗셈펑션을 컴파일러에 결합하는것이좋다 왜냐하면 나눗셈펑션은 항상 나눈값과 나머지를 리턴하기 필요하다 만약둘다 필요하다면 우리는 이와같은 예제를 같이 쓸수있어야한다
    int func_div_and_mod (int a, int b) { 
            return (a / b) + (a % b); 
        } 
     

    4.4 1 부터 n 까지 더하기

    for (i = 0; i < n; i++) 
       sum += i; 
     
    보다는 아래가 낫다.
    n(n+1) * 0.5 
     
    천재 수학자의 어린시절 이야기를 들은 기억이 있다. 자리를 비운 사이 얘들이 놀지 못하게 하려고 1부터 100까지 더하라는 문제를 냈는데, 5분만에 풀고 놀았더란 얘기다. (수학자 파스칼의 어린시절 얘기이던가 가물가물 하다.)

    어떻게 풀었냐고 물어봤더니. "1+100, 2+99, 3+98"이게 50번 반복되더라는 것이어서 101*50 해서 답을 구했다고 대답했다고 한다. 이것을 대수로 나타내면 n(n+1) * 0.5 이 나온다.

    약간만 수학적으로 머리를 굴리는 것으로 매우 큰 효과를 얻을 수 있다. 시간나면 대수학을 공부해보도록 하자.

    4.5 짝수 홀수 확인

    비트연산을 잘 이용하면 간단하게 검사할 수 있다.
    1234 & 1 ? printf("짝수\n"):printf("홀수\n"); 
    이런 방법도 가능하다. 
    1234 << 31 ?  printf("짝수\n"):printf("홀수\n"); 
     
    당연히 % 연산보다 훨씬 효율적이다.

    4.6 2의 배수로 나누기

    나누기를 할 때 2의 배수를 분자로 함으로써, 코드를 더 효율적으로 만들 수 있다. 이경우에 컴파일러는 나누기 연산대신에 shift 연산을 할 수 있기 때문이다. shift 연산은 가장빠른 연산중의 하나다. 그러므로 가능하면 2의 배수로 나눌 수 있도록 스케일을 조절할 필요가 있다. (예를 들어 66으로 나누어야 한다면 64로 나눌 수 있도록 스케일을 조절하라).
    typedef unsigned int uint; 
     
     uint div32u (uint a) { 
       return a / 32; 
     } 
     int div32s (int a){ 
       return a / 32; 
     } 
     
    이경우에도 signed 값보다는 unsigned 로 나누어질 수 있도록 함수를 조절할 필요가 있다. signed의 경우에는 더많은 시간이 소비된다. 왜냐하면 오른쪽으로 쉬프트 시킬경우 가장왼쪽의 비트를 0으로 만들어주는 연산이 한번더 들어가기 때문이다. 

    #include <stdio.h> 
     
    int main() 
    { 
      unsigned int a = 1024; 
      unsigned b, c; 
      b = a/32;    // --- 1 
      c = a >> 5;  // --- 2 
    } 
     
    1과 2는 동일한 결과를 보여주며, 컴파일러내에서도 동일하게 shift 처리된다. 다음은 intel 프로세서에서 gcc로 컴파일된 어셈블리어중 1과 2에 해당되는 부분의 코드다. 
    movl    $1024, -12(%ebp) 
    movl    -12(%ebp), %eax 
    shrl    $5, %eax           # b = a / 32 
    movl    %eax, -8(%ebp) 
    movl    -12(%ebp), %eax 
    shrl    $5, %eax           # c = a >> 5 
     

    4.7 Binary Breakdown

    여러개의 조건을 검사하다 보면, if와 else if를 여러개 사용하는 경우가 생긴다.
    if(a==1) {  
    } else if(a==2) {  
    } else if(a==3) {  
    } else if(a==4) {  
    } else if(a==5) {  
    } else if(a==6) {  
    } else if(a==7) {  
    } else if(a==8)  
     
    {  
    } 
     
    이경우 2개로 나누어서 조건 검사를 하도록 한다.
    if(a<=4) {  
        if(a==1)     {  
        }  else if(a==2)  {  
        }  else if(a==3)  {  
        }  else if(a==4)   {  
       
        }  
    }  
    else  
    {  
        if(a==5)  {  
        } else if(a==6)   {  
        } else if(a==7)  {  
        } else if(a==8)  {  
        }  
    } 
     
    이렇게 하면 최악의 경우 비교횟수가 절반이 됨을 알 수 있다. 필요에 따라서는 아래와 같이 3중루프 코드로 만들 수도 있다. 좀더 빠르게 동작하긴 하겠지만 코드가 보기 어려워진다는 단점이 생긴다.
    if(a<=4)  
    {  
        if(a<=2)  
        {  
            if(a==1)  
            {  
                /* a is 1 */  
            }  
            else  
            {  
                /* a must be 2 */  
            }  
        }  
        else  
        {  
            if(a==3)  
            {  
                /* a is 3 */  
            }  
            else  
            {  
                /* a must be 4 */  
            }  
        }  
    }  
    else  
    {  
        if(a<=6)  
        {  
            if(a==5)  
            {  
                /* a is 5 */  
            }  
            else  
            {  
                /* a must be 6 */  
            }  
        }  
        else  
        {  
            if(a==7)  
            {  
                /* a is 7 */  
            }  
            else  
            {  
                /* a must be 8 */  
            }  
        }  
    } 
     

    4.8 배열을 이용한 index 생성

    특정값에 대응되는 문자를 변수에 입력하는 코드를 만든다면 다음과 같이 switch 문을 사용할 것이다.
    switch ( queue ) { 
      case 0 :   letter = 'W'; 
         break; 
      case 1 :   letter = 'S'; 
         break; 
      case 2 :   letter = 'U'; 
         break; 
    } 
     
    혹은 if else 문을 사용할 수도 있을 것이다.
     if ( queue == 0 ) 
       letter = 'W'; 
     else if ( queue == 1 ) 
       letter = 'S'; 
     else 
       letter = 'U'; 
     

    다음과 같이 문자의 배열을 인덱스화 하면 더 빠른 접근이 가능하다. - 사용하기도 쉽다 -
    static char *classes="WSU"; 
    letter = classes[queue]; 
     

    4.9 나머지 연산자의 대체

    우리는 나눗셈의 나머지를 알기 위해서 나머지 연산자 %를 사용한다. 이경우 % 연산대신 판단문을 사용해서 시간을 줄일 수 있다. 아래의 두 코드를 비교해 보기 바란다.
    uint modulo_func1 (uint count) 
    { 
       return (++count % 60); 
    } 
     
    uint modulo_func2 (uint count) 
    { 
       if (++count >= 60) 
      count = 0; 
      return (count); 
    } 
     
    if 문은 나머지 연산자보다 빠른코드를 생성한다. 주의 할점은 2번째 함수의 경우 0에서 60사이의 값에 대해서만 제대로 측정이 된다는 점이다. 


    4.10 Using Aliases

    아래의 코드를 보기 바란다.
      void func1( int *data )    { 
          int i; 
     
         for(i=0; i<10; i++)  
         { 
                anyfunc( *data, i); 
         } 
      } 
     

    *data 가 결코 변하지 않는다고 하더라도, anyfunc 함수를 호출하는 컴파일러는 이걸 알 수가 없다. 그래서 변수가 사용될 때마다 메모리로 부터 다시 읽어들이게 된다. 이 문제는 지역변수를 하나더 둠으로써 해결할 수 있다. 
      void func1( int *data ) 
      { 
          int i; 
          int localdata; 
     
          localdata = *data; 
          for(i=0; i<10; i++) 
          { 
              anyfunc ( localdata, i); 
          } 
      } 
     

    5 데이터 타입

    C 컴파일러는 char, short, int, long, float, double 등의 다양한 원시 데이터 타입을 제공한다. 필요한 영역에 필요한 수준의 데이터 타입을 사용하도록 하자. 

    5.1 전역 변수

    전역 변수는 절대 레지스터에 할당할 수 없다. 포인터를 사용하여 간접적으로 할당하거나 함수호출을 이용해서 전역변수를 변환할 수 있다. 

    따라서 컴파일러는 전역변수의 값을 레지스터에 올려서 캐쉬할 수 없게 되고 때문에 글로벌 변수를 이용할 때마다 다시 읽어들이는 오버로드가 생기게 된다. 그러므로 가능하면 글로벌 변수를 직접 호출하는 대신에, 로컬변수를 이용해서 필요한 연산을 하고 그 결과를 글로별 변수에 할당하는 방법을 사용해야 한다. 
    int f(void); 
    int g(void); 
    int h(void); 
    int errs; 
    void test1(void) 
    { 
      errs += f(); 
      errs += g(); 
      errs += h(); 
    } 
    void test2(void) 
    { 
      int localerrs = errs; 
      localerrs += f(); 
      localerrs += g(); 
      localerrs += h(); 
      errs = localerrs; 
    } 
     
    test1은 매번 전역변수를 로드해야 한다. 반면 test2의 경우 레지스터에 등록된 localerrs에 값을 저장하고 마지막에 한번만 전역변수에 접근함을 알 수 있다. 

    5.2 지역변수

    가능하면 지역변수로 char 이나 short를 사용하지 않도록 한다. char와 short가 사용될 경우 컴파일러는 값을 저장하기 위해서 8bit 혹은 16bit를 할당한 후, 남는 크기를 줄이는 작업을 하게 된다. 이는 24bit, 16bit 만큼을 shift 시키는 연산을 하게 됨을 의미한다. 그러므로 입력되는 데이터가 8 혹은 16 비트라고 하더라도, 32bit로 연산을 하도록 함수를 만들 필요가 있다. 
    int wordinc (int a) 
    {  
       return a + 1; 
    } 
    short shortinc (short a) 
    {  
        return a + 1; 
    } 
    char charinc (char a) 
    {  
        return a + 1; 
    } 
     
    3번째 코드가 가장 빠른결과를 보여줄 것이라고 생각할지도 모르지만, 1번째 코드가 가장 빠르게 작동한다.

    5.3 포인터

    구조체를 그대로 넘길경우 구조체의 모든 값이 스택에 올라가기 때문에 느리게 작동한다. 그래서 구조체의 포인터를 넘기는 경우가 많다. 나는 수 kbyte의 구조체를 넘기는 프로그램을 본적이 있다. 이런 경우 포인터를 쓰도록 하자.

    포인터를 통해서 구조체를 넘길때, 구조체의 멤버를 수정할일이 없다면 상수로 선언해서 넘기도록 하자. 
    void print_data_of_a_structure ( const Thestruct  *data_pointer) 
    { 
       ...printf contents of the structure... 
    } 
     
    이렇게 하면 컴파일러는 인자로 넘어온 포인터가 수정할 수 없는 외부 구조체라는 것을 알게 된다. 이렇게 되면, 값이 사용될 때마다 다시 읽혀질 필요가 없어지게 된다. 또한 이러한 코드는 실수로 구조체 멤버의 변수를 바꾸는 것과 같은 실수를 하지 않도록 해준다.

    5.4 Pointer chains

    구조체내의 정보에 접근하려다 보면 포인터의 chain을 사용해야 할 때가 있다. 다음과 같은 경우다.
    typedef struct { int x, y, z; } Point3; 
    typedef struct { Point3 *pos, *direction; } Object; 
     
    void InitPos1(Object *p) 
    { 
       p->pos->x = 0; 
       p->pos->y = 0; 
       p->pos->z = 0; 
    } 
     
    이럴 경우 p->pos 를 다른 포인터에 할당해서 접근하도록 하자. 이렇게 하면 p->pos 가 캐쉬되므로 좀더 효율적으로 작동하게 된다.
    void InitPos2(Object *p) 
    {  
       Point3 *pos = p->pos; 
       pos->x = 0;  
       pos->y = 0; 
       pos->z = 0; 
    } 
     
    코드가 좀더 보기 좋아진다는 효과도 노릴 수 있다. 

    5.5 Switch 대신 lookup table 를 사용하라

    switch는 다음과 같은 경우 사용한다.
    • 여러개의 함수중 하나를 호출해야할 필요가 있을 때
    • 다양한 리턴값을 넘겨받고 이를 처리해야 할때
    • 여러개의 코드중 하나를 실행시켜야 할때

    예를 들어서 조건값을 입력받아서 거기에 맞는 문자열을 리턴하는 아래와 같은 코드가 있다고 가정해보자.
    char * Condition_String1(int condition) { 
      switch(condition) { 
         case 0: return "EQ"; 
         case 1: return "NE"; 
         case 2: return "CS"; 
         case 3: return "CC"; 
         case 4: return "MI"; 
         case 5: return "PL"; 
         case 6: return "VS"; 
         case 7: return "VC"; 
         case 8: return "HI"; 
         case 9: return "LS"; 
         case 10: return "GE"; 
         case 11: return "LT"; 
         case 12: return "GT"; 
         case 13: return "LE"; 
         case 14: return ""; 
         default: return 0; 
      } 
    } 
     
    위의 코드는 아래와 같이 좀 더 효율적인 코드로 만들 수 있다. 덤으로 보기에도 편하다.
    char * Condition_String2(int condition) { 
       if ((unsigned) condition >= 15) return 0; 
          return 
          "EQ\0NE\0CS\0CC\0MI\0PL\0VS\0VC\0HI\0LS\0GE\0LT\0GT\0LE\0\0" + 
           3 * condition; 
    } 
     
    첫번째 루틴은 240byte가 필요하지만 두번째 루틴은 72바이트만 소모되고 있다.

    6 루프

    루프는 모든 프로그램에서 사용되는데, 많은 경우 루프에서 과다한 시간을 소비하게 된다. 여러번 실행되는 루프틔 특성상 조그마한 시간의 낭비가 게속 누적되기 때문이다. 

    6.1 Loop termination

    루프를 종료시키기 위한 검사는 항상 count-down-to-zero 방식을 사용하도록 한다. 이것은 좀더 적은 시간을 소비한다. 아래의 두개의 예제는 동일한 일을한다. 다른점이 있다면 첫번째 코드는 루프를 증가시킨다는 점이고 두번째는 루프를 감소시킨다는 점이다. 
    int fact1_func (int n) 
    { 
        int i, fact = 1; 
        for (i = 1; i <= n; i++) 
          fact *= i; 
        return (fact); 
    } 
     
    int fact2_func(int n) 
    { 
        int i, fact = 1; 
        for (i = n; i != 0; i--) 
           fact *= i; 
        return (fact); 
    } 
     

    6.2 더욱 빠른 for 문

    다음은 0부터 10까지의 숫자를 연산하기 위해서 for 문을 사용한 일반적인 예다.
    for (i = 0; i < 10; i++) {...} 
     
    i는 0,1,2,3,4,5,6,7,8,9 로 1씩 증가할 것이다.

    가능하면 아래와 같이 숫자를 감소시키는 방향으로 for 문을 사용하라.
    for (i = 10; i--;) {...} 
     
    첫번재 코드보다 두번째 코드가 더 빠른 수행능력을 보여준다. 

    두번째 코드는 i가 0이 아니면 i를 감소시키고 다음 코드를 진행하라의 의미인데, 조건 검사의 경우 0인지 아닌지를 비교하는데 더 작은 시간이 소비되기 때문이다. 그러므로 두번째 코드는 아래와 같이 재작성할 수 있다. 두번째 예제코드 보다는 아래의 코드가 더 보기 쉬우므로, 아래의 코드를 사용하는게 가독성 측면에서 유리할 것이다.
    for (i = 10; i ; i--) { } 
    혹은  
    for (i = 10; i!=0; i--) { } 
     
    이들은 모두 동일한 수행능력을 보여준다. 

    6.3 Loop jamming


    6.4 함수 루프

    함수는 호출되기 위한 분명한 오버헤드가 존재한다. 실행해야될 함수가 있는 포인터만 변경하는게 아닌, 값들을 stack에 push하는 것과 새로운 변수의 할당과 같은 작업이 수행되기 때문이다. 때문에 루프에서 함수를 호출하는 등의 코드는 작성하지 않는게 좋다. 이런류의 코드는 반대로 함수에서 루프를 수행하도록 변경하는걸 추천한다. 

    for(i=0 ; i<100 ; i++)  
    {  
        func(t,i);  
    }  
    -  
    -  
    -  
    void func(int w,d)  
    {  
        lots of stuff.  
    } 
     

    위의 코드는 아래처럼 바꿀 수 있다. 동일한 일을 좀더 빠르게 수행할 수 있다.
    func(t);  
    -  
    -  
    -  
    void func(w)  
    {  
        for(i=0 ; i<100 ; i++)  
        {  
            //lots of stuff.  
        }  
    } 
     

    6.5 Population count - 비트 계수하기

    아래의 코드는는 주어진 값에 1bit가 몇개인지를 검사하는 코드다. 0000 1010 이라면 2를 리턴하는 식이다. 이러한 비트필드는 일정한 범위의 값이 참인지 거짓인지를 빠르게 체크하기 위해서 널리 사용될 수 있다. 

    다음과 같이 1씩 오른쪽으로 쉬프트 하면서, & 연산을 한다. 
    int countbit1(uint n) 
    { 
      int bits = 0; 
      while (n != 0) 
      { 
        if (n & 1) bits++; 
        n >>= 1; 
       } 
      return bits; 
    } 
     

    이 코드는 다음과 같이 4만큼 쉬프트 하는 식으로 바꿔서, 성능을 높일 수 있다.
    int countbit2(uint n) 
    { 
       int bits = 0; 
       while (n != 0) 
       { 
          if (n & 1) bits++; 
          if (n & 2) bits++; 
          if (n & 4) bits++; 
          if (n & 8) bits++; 
          n >>= 4; 
       } 
       return bits; 
    } 
     

    6.6 Earyl loop breaking

    루프를 사용하다보면, 일정 조건이 만족되면 뒤의 프로세스가 더이상 필요 없어지는 경우가 있다. 이 경우에는 break를 이용해서 루프를 벗어나도록 한다.
    found = FALSE;  
    for(i=0;i<10000;i++)  
    {  
        if( list[i] == -99 )  
        {  
            found = TRUE;  
        }  
    }  
     
    if( found ) printf("Yes, there is a -99. Hooray!\n"); 
     

    위의 코드는 -99가 포함되어 있는지 아닌지를 확인하는 프로그램이므로, 일단 발생이 되었다면, 루프를 돌 필요가 없다. 아래와 같이 break 문으로 빠져나가면 쓸데없는 루프의 낭비를 줄일 수 있다.
        found = FALSE;  
        for(i=0; i<10000; i++)  
        {  
            if( list[i] == -99 )  
            {  
                found = TRUE;  
                break;  
            }  
        }  
        if( found ) printf("Yes, there is a -99. Hooray!\n"); 
     

    6.7 Loop 사용하지 않기

    몇번만 순환하는 루프의 경우 풀어쓰면 성능을 향상시킬 수 있다 - 코드가 좀더 커지긴 한다 -. 루프를 사용하지 않게 되면, 카운터를 유지하고 업데이트하고 비교하는 작업이 그만큼 줄어들게 된다.
    for(i=0; i<3; i++){  
        something(i); 
    } 
     
    보다는 아래의 코드가 더 효율적이다.
    something(0); 
    something(1); 
    something(2); 
     

    여하간에 가능하면 루프를 줄이는게 더 효율적이다. 아래의 코드는 한번의 루프에서 블럭단위로 함수를 호출함으로써, 루프의 수를 줄이고 있다.
    //Example 1 
     
    #include<STDIO.H>  
     
    #define BLOCKSIZE (8)  
     
    void main(void) 
    {  
    int i = 0;  
    int limit = 33;  /* 33 번 함수를 호출한다 */  
    int blocklimit;  
     
    /* The limit may not be divisible by BLOCKSIZE,  
     * go as near as we can first, then tidy up. 
     */  
    blocklimit = (limit / BLOCKSIZE) * BLOCKSIZE;  
     
    /* 한번의 루프에서 8번의 함수를 호출해서 루프의 순환횟수를 줄이고 있다. */  
    while( i < blocklimit )  
    {  
        printf("process(%d)\n", i);  
        printf("process(%d)\n", i+1);  
        printf("process(%d)\n", i+2);  
        printf("process(%d)\n", i+3);  
        printf("process(%d)\n", i+4);  
        printf("process(%d)\n", i+5);  
        printf("process(%d)\n", i+6);  
        printf("process(%d)\n", i+7);  
     
        /* counter 업데이트 */  
        i += 8;  
     
    }  
     
    /*  
     * 8의 배수만큼 함수를 호출하고 있으므로, 처리하지 못한 함수가 생긴다. 
     * 아래에서 처리하지 못한 함수를 호출한다. 
     */  
     
    if( i < limit )  
    {  
        /* Jump into the case at the place that will allow 
         * us to finish off the appropriate number of items.  
         */  
     
        switch( limit - i )  
        {  
            case 7 : printf("process(%d)\n", i); i++;  
            case 6 : printf("process(%d)\n", i); i++;  
            case 5 : printf("process(%d)\n", i); i++;  
            case 4 : printf("process(%d)\n", i); i++;  
            case 3 : printf("process(%d)\n", i); i++;  
            case 2 : printf("process(%d)\n", i); i++;  
            case 1 : printf("process(%d)\n", i);  
        } 
    }  
     
    } 
     

    7 함수 디자인

    함수를 작고 가볍게 많드는건 좋은 생각이다. 이렇게 함으로써 컴파일러는 register 할당과 같은 영역에서 좀더 쉽게 최적화 할수 있게 된다.

    7.1 함수 호출 Overhead

    프로세서에서 함수의 호출은 예상과 달리 그리 큰 비용이 들지는 않는다. 함수가 호출되면 register에 함수의 인자를 넘기게 된다. 이 인자들은 char, short, int, float, structure등이 올 수 있다. 이들 인자는 실제 4개만을 전달할 수 있다는 한계를 가진다. 이 이상으로 인자가 넘어가게 되면, stack를 이용해서 함수의 인자를 넘기게 된다. 당연히 함수를 호출함에 있어서 OverHead가 발생하게 된다. 함수호출시 발생하는 인자의 제한에 대해서는 Linux에서의 Assembly문서를 참고하기 바란다.

    예제코드
        int f1(int a, int b, int c, int d) {  
           return a + b + c + d; 
        } 
     
        int g1(void) { 
           return f1(1, 2, 3, 4); 
        } 
     
     
        int f2(int a, int b, int c, int d, int e, int f) { 
          return a + b + c + d + e + f; 
        } 
     
        ing g2(void) { 
         return f2(1, 2, 3, 4, 5, 6); 
        } 
     
    6개의 인자를 사용하는 f2와 g2함수는 스택에 저장되어 있는 인자를 꺼내기 위해서 2번의 메모리 접근이 더 발생하게 된다.

    7.2 가능한 인자의 수를 줄여라

    그러므로 가능한 적은 수의 인자를 넘겨받도록 함수를 설계할 필요가 있다.
    • 4개 이하의 인자를 가지도록 함수를 설계하라. 4개가 넘어가면 스택을 통해서 인자를 넘기게 된다.
    • 만약 함수가 4개 이상의 인자가 사용되면, 스택을 통해서 인자를 넘기게 되고 스택의 크기만큼 메모리 접근이 발생하게 된다.
    • 이럴 경우 구조체를 선언하고, 구조체에 대한 포인터를 넘기는 방식을 사용하도록 한다.
    • 구조체를 사용하면 인자의 양을 줄일 수 있으며, 코드 활용성도 높아지게 된다. 
    • 인자에 사용되는 자료형은 long크기 이상으로 하도록 하자.
    • 가변인수를 사용하지 말라. 가변인수를 사용하게 되면, 인자가 stack으로 넘어가게 된다.

    7.3 인라인 함수

    __inline키워드를 이용하면 함수를 인라인화 할 수 있게 된다. 이것은 일종의 매크로 처럼 작용을 하며, 함수가 호출되는 대신 함수의 본체가 직접 치환이 되어 버린다. 이렇게 함으로써, 함수를 호출하는데 드는 비용을 줄일 수 있게 된다. 반면 코드가 모두 치환되어 버리므로, 코드의 크기가 커지게 된다.
        __inline int square(int x) { 
           return x * x; 
        } 
     
        #include <MATH.H> 
     
        double length(int x, int y){ 
            return sqrt(square(x) + square(y)); 
        } 
     
    인라인 함수를 이용함으로써 얻을 수 있는 이득은 다음과 같다.
    • 함수호출을 위한 비용이 발생하지 않는다. 코드를 직접 읽어들이기 때문이다.
    • 일반적으로 인자를 넘기는 방식은 변수를 복사하는 것보다 적은 비용이 든다. 만약 인자가 상수라면 컴파일러는 더욱 높은 수준의 최적화를 할 수 있을 것이다.

    Posted by 생각처럼
    , |
    persnal/Android
    모토쿼티 OpenRecovery 3.3 설치
    2011/04/06 23:27
    네이버 안드로이더스 에 올린 글

    -----------------------------------------------------------------------------------------

    음... 쿼티방에서는 대부분 1.4 버전apk 설치를 하고 3.3 으로 바꿔치기 하는 방법을 사용하시더군요

    http://forum.xda-developers.com/showthread.php?t=926979

    이 방법대로 설치가 가능합니다

    1.4 -> 3.3 하실 필요없이 바로 3.3 설치를 하시면 됩니다

    3.3 을 다운받으시고

    SDcard 에 넣습니다

    update.zip 가 가장 상위에 ( /sdcard ) 그리고 OpenRecovery 디렉토리까지.. (/sdcard/OpenRecovery )

    루팅 되어있어야 하며 adb 가 있어야 합니다

    adb shell
    $su
    #cp /sdcard/OpenRecovery/orbootstrap/install_script.sh /tmp
    #chmod 755 /tmp/install_script.sh
    #/tmp/install_script.sh STR

    이러면 설치가 끝났습니다

    reboot 시킵니다..

    그런데 이 방식으로 하면 문제가 하나 있습니다

    순정리커버리를 통해 들어간 다음 Apply update.zip 를 해야 오픈리커버리로 진입이 됩니다

    원래는 전원버튼 켤때 M 로고 나올때 볼륨업 을 누르고 있으면 진입이 해야하는건데 말이죠..

    이때 순정을 통해 들어갈때의 메시지를 곰곰히 살펴보았습니다

    항상 인스톨을 하더군요.. (인스톨이 안되었다.. 어쩌고 하면서)

    그래서 update.zip 를 OpenRecovery.zip 로 이름을 바꾸었습니다

    (저는 "복사" 했습니다. 순정리커버리를 통해서 들어올 수 있는 방법도 남겨놓으려고..)

    그러면 전원 나갔다 들어오며 "M" 로고 뜰때 "볼륨업" 을 누르고 있으면

    오픈리커버리로 진입을 합니다

    이 경우는 벽돌이 되어도 마찬가지로 진입이 됩니다

    (일부러 벽돌만들어 테스트 해보았습니다)

    벽돌되면 rsd 로 sbf 미는 방법밖에 없다는 글이 자꾸 보여서 일부러 이 글을 적습니다

    도움이 되기를 바랍니다
    Posted by 생각처럼
    , |
    error: more than one device and emulator 

    adb kill-server
    adb start-server 로 하시고

    adb shell 하면됨
    Posted by 생각처럼
    , |

    도메인 등록방법 및 국내 및 해외 도메인 등록업체 종류

    제작한 홈페이지를 인터넷에서 운영하기 위해서는 도메인이 필요합니다. 물론 호스팅업체에서 제공하는 도메인(예:YourID.site.com)이 있지만 보기에도 좋지 않으며 호스팅을 옮겨야 할 경우 해당 도메인을 사용할 수 없게 되어 기존의 도메인으로 방문하던 방문자와 링크를 모두 잃게 되게 됩니다. 단순한 연습용 홈페이지가 아니라면, 호스팅은 무료를 이용하게 되더라도 도메인만큼은 구입해 놓는게 좋습니다.

    검색엔진의 관점에서 본다면 도메인은,

    • 새로 등록한 것보다는 오래된 것이 좋습니다.
    • 사이트의 핵심 키워드가 들어간 것이 좋습니다. 특히 불필요한 단어없이 검색어와 완전히 일치하는 도메인네임이 좋습니다.
    • 영어로 된 글로벌 사이트라면 gTLD(generic Top Level Domain)으로 ‘com’이 좋으며 ‘net’이나 ‘org’도 좋습니다.
    • 특정 국가의 도메인(ccTLD : country code Top Level Domains)은 해당 국가내에서 검색시에 검색결과에서 조금 더 중요하게 봅니다. 즉 한글 홈페이지면 gTLD도 좋지만 co.kr을 선택하는 것도 좋습니다.

    방문자의 입장에서는,

    • 짧고 간결하고 기억하기 쉬운 것이 좋습니다.
    • 사이트의 내용과 관련이 있는 도메인이 좋습니다.
    • 사이트 주소의 정확한 TLD가 기억이 나지 않을 때 com 이나 co.kr을 먼저 시도해 보는 경향이 있습니다.

    위와 같은 것들을 고려해서 도메인을 선택해야 하는데 크게 두가지 방법이 있습니다.

    • 도메인에 키워드를 사용 – 해당 키워드에 대해서 경쟁이 치열할 경우 사용하면 좋습니다.
    • 브랜드화된 도메인 사용 – 제작하려고 하는 홈페이지의 키워드가 뚜렷하지 않거나 여러가지일 경우 짧고 기억하기 쉬운 도메인 네임을 사용하는 것도 좋습니다. 장기적으로 사이트를 운영하려고 할 때 적합합니다. google.com, yahoo.com, last.fm, mar.gar.in 등과 같은 사이트들이 이에 해당한다고 할 수 있습니다.

    도메인 등록방법 및 검색

    종류

    인터넷을 사용하면서 일반인이 접할 수 있는 도메인은 아래와 같이 크게 두 종류가 있습니다.

    • 일반 최상위 도메인(gTLD : generic Top Level Domain) – 국가에 제한을 받지 않으며 도메인의 끝의 확장자가 한단어(TLD : Top Level Domain)로 이루어져 있습니다. 수백개에 달하는 ccTLD와는 달리 그 수가 별로 많지 않습니다. com, org, net, info, edu, gov, int, mil, aero, biz, coop, museum, name, pro, cat, jobs, mobi, post, tel, travel, asia 정도 있다고 보시면 됩니다.
    • 국가 최상위 도메인(ccTLD : country code Top Level Domain) – kr, us, uk, …와 같이 국가별로 주어진 도메인으로 co.kr, or.kr, go.kr, co.uk 와 같이 TLD 앞에 차상위 도메인(SLD : Second Level Domain)이 붙기도 합니다.

    위와 같은 도메인이 모두 등록 가능한 것은 아닙니다. 자신이 살고 있는 국가나, 특정 자격 조건에 의해 등록할 수 있는 것이 있고 없는 것도 있습니다. 한국에 거주하는 일반 사용자들이 등록할 수 있는 도메인은 대락 다음과 같습니다.

    • 일반 최상위도메인 – com, org, net, info, biz, name, mobi, tel, asia
    • 국가 최상위도메인 : 인구가 아주 적은 국가의 ccTLD의 경우에 사용 가능한 도메인이 많이 남기 때문에 정책적으로 해당 국가에 거주하지 않더라도 등록이 가능한 경우도 있습니다. – me, ms, gs, be, cc, ws, tv, bz, lu, mx, ly, am, fm, nu, la, io …
    • kr 도메인 – kr, co.kr, pe.kr

    국내 도메인 등록업체

    가비아, 호스팅케이알 ,아이네임즈, 미리내, 블루웹 등 국내에는 많은 도메인 업체들이 있습니다. 따져 보면 비싼 곳도 있고, 상대적으로 저렴한 업체도 있고, 제공하는 서비스도 조금씩 차이가 있지만, 기본적인 기능은 다 제공하고 있기 때문에, 어떤 업체를 선택하더라도 사용에 별 지장은 없습니다. 해당 업체들에 대한 자세한 가격과 정보들은 이 페이지 상단에 있는 유,무료 도메인 메뉴에 자세히 나와 있습니다.

    해외 도메인 등록업체

    좀 더 다양한 국제 도메인을 원한다면 해외 도매인 등록업체를 알아 볼 수도 있습니다. 그리고 일반적으로 com, org, net, info 등의 도메인은 국내의 업체보다 저렴합니다. 결제는 보통 신용카드나 페이팔로 가능합니다. 페이지 상단에 있는 ‘유,무료 도메인’ 메뉴에 해외 도메인 업체에 대한 자세한 정보가 나와 있습니다.

    Godaddy.com – 국내에서도 널리 알려진 업체로 com, org, info, net 등의 도메인 가격이 싼 편입니다.
    Moniker – 아주 다양한 도메인을 검색하고 구매할 수 있습니다.
    1&1.com – 도메인과 호스팅을 동시에 이용할 경우 좋은 조건이 많이 있습니다. 타 업체와 달리 주민등록증이나 여권같은 신분증을 요구할 수도 있습니다.

    도메인 검색

    도메인 검색은 도메인 등록기관(등록 대행 업체)를 통해서 가능하며 특별히 어려운 점은 없습니다. 각 업체마다 보통 아래 스크린샷과 같은 검색창이 있는데 원하는 도메인을 입력하고 검색하면 등록가능 여부를 확인해 볼 수 있습니다.

    도메인 등록

    도메인을 등록한다는 것은 해당 도메인을 일정기간 사용하겠다는 것을 뜻합니다. 영원히 자신의 소유가 되지 않습니다. 짧게는 1년 길게는 10년 정도의 기간이 가능하며, 만료기간이 되면 다시 연장이 가능하므로 소유기간을 짧게 해도 됩니다. 도메인 등록방법은 인터넷 쇼핑몰 결제보다 더 간단해서 특별히 설명할 부분이 없습니다. 한가지 주의할 점은 꼭 자신의 명의로 등록해야 합니다. 나중에 소유권을 변경하거나 할 때 문제가 발생할 수 있습니다.

    낙장 도메인

    도메인의 소유자가 만료일까지 도메인을 연장하지 않을 경우, 만료일이 끝나고 한달 정도 지나면 누구나 그 도메인을 구매할 수 있게 되는데, 이것을 낙장 도메인이라고 합니다. 낙장도메인이 좋은 점은,

    • 만약 해당 도메인으로 실제로 사이트가 운영되었다면 다른 사이트로 부터 해당 도메인으로 링크가 많이 걸려 있을 수 있습니다.
    • 구글에 비해 야후나 msn 검색엔진의 경우 새로 등록한 도메인이 검색결과에 나오는데 좀 시간이 많이 걸립니다. 그리고 오래된 도메인이 검색결과에서 좀더 상위에 랭크될 수 있습니다. 잘 찾아보면 등록기간이 4~5년 이상인 낙장도메인이 꽤 있습니다.

    낙장도메인의 정보는 등록업체에서 제공하기도 하며, nakjang.kr에서도 자세히 검색해 볼 수 있습니다. 좋은 도메인일 경우 경쟁이 치열해서 낙장 당일날 등록하기 힘들 수 있으므로, 등록업체에서 예약을 해 두는게 좋습니다. 이 경우 예치금으로 비용이 약간 더 들어가게 됩니다. 그리고 경쟁이 치열한 도메인일 경우, 예약한다고 해서 반드시 등록되지는 않습니다. 등록실패의 경우는 대부분 환불은 안되고, 그 예치금으로 다른 도메인을 예약하거나 구매할 수 있습니다.

    광고 없는 무료도메인

    도메인 중에는 등록비용 없이 무료로 사용할 수 있는 것들도 있습니다. 대부분 이런 것들은, 네임서버 변경을 해주는 것이 아니라 단순히 포워딩만을 해주며, 또한 접속시 팝업창 같은 광고가 뜨는 것도 있습니다.

    하지만 무료 도메인 중에도, 아래와 같이, 네임서버를 지원하면서 광고도 없는 것들도 몇 개 있습니다. 페이지 상단에 있는 ‘유,무료 도메인’ 메뉴에 무료 도메인에 대한 자세한 정보가 나와 있습니다.

    co.cc – 가장 유명한 무료도메인으로 국내업체입니다. 네임서버를 지원하며 광고도 없고, 일반 도메인처럼 사용이 가능합니다. 하지만 상업적인 용도로 사용시에는 소액의 비용이 발생합니다.
    cz.cc – 해외 업체로 co.cc와 비슷합니다. 아직까지는 무료라고 말하고 있지만 co.cc처럼 시간이 지나면 상업적인 용도로 사용시 돈을 내야한다는 조건을 걸지도 모릅니다.
    Tk – ‘yoursite.tk’와 같은 형식으로 도메인 사용이 가능합니다. 네임서버와 포워딩을 지원하고 한국어 설명도 지원하고 있습니다.

    네임서버(DNS: Domain Name System) 변경하기

    호스팅업체의 호스트는 숫자로 된 네자리의 고유주소(IP:Internet Protocol)를 가지고 있습니다. 도메인이 없어도 브라우저에 이 IP를 입력하면 자신의 호스팅으로 연결이 됩니다. 도메인은 사람들이 사용하기 편하게 하기 위해 사용하는 것으로, 도메인을 구입한 후에는 사용하고 있는 호스팅업체의 호스트의 IP로 구입한 도메인을 연결해야합니다. 네임서버(DNS)는 ‘Domain Name System’의 줄임말로 각각의 도메인을, 해당하는 IP 주소로 연결시켜주는 역할을 합니다.

    KR도메인의 경우 과거에는 네임서버 변경을 KRNIC 에서 했습니다. 지금은 등록기관의 홈페이지를 통해서 해당 호스팅업체의 네임서버로 바로 변경할 수 있습니다.

    우선 사용하고 있는 웹호스팅업체의 홈페이지로 가서 네임서버를 알아냅니다. 보틍은 왼쪽 그림처럼 사이트의 메인페이지에 나와 있습니다. 비상시를 대비해서 보통 네임서버 주소는 2~5개 정도가 됩니다.

    호스팅 업체의 네임서버 주소를 야래 그림처럼, 도메인 등록업체의 네임서버 정보 관리창에 그대로 복사해서 입력하면 됩니다. 그러면 네임서버가 도메인 등록기관에서 호스팅업체로 변경이 됩니다. 보통 1~3일 정도 후면 브라우저에 도메인을 입력하면 자신의 호스팅으로 연결이 됩니다.

    추후에 호스팅 업체를 바꾸게 될 경우, 위의 도메인 등록업체의 관리창에 그 호스팅업체의 네임서버로 변경해서 입력하면 호스팅업체를 바꾸더라도 똑같은 도메인으로 아무 이상없이 웹사이트를 계속 운영할 수 있게 됩니다.

    Posted by 생각처럼
    , |

    최근에 달린 댓글

    최근에 받은 트랙백

    글 보관함