なんだかGoodVibes

日々の勉強メモです。

【C】[超入門] 共有ライブラリを作成する

こんにちは。
本日は、C言語メモです。

概要

C言語の共有ライブラリの作成と
共通ライブラリのリンクを方法について記載します。

動作環境はMacなので、
本記事で作成する共有ライブラリの拡張子は
dylibとなります。


共有ライブラリの作成とリンク

以下のディレクトリ構成とします。

include
 ┗ calc.h
common
 ┗ calc_add.c
myapp
 ┗ main.c

各ファイルの内容は以下です。

  • calc.h
#ifndef CALC_H
#define CALC_H

extern void add(int num1, int num2);

#endif // CALC_H
  • calc_add.c
#include <stdio.h>

void add(int num1, int num2) {
    int result = 0;
    result = num1 + num2;

    printf("%d + %d = %d\n", num1, num2, result);
}
  • main.c
#include "calc.h"

int main() {

    add(100, 200);
    return 0;
}
共通ライブラリの作成

common配下のソースから共有ライブラリを作成します。

$ gcc -fPIC -c calc_add.c -I../include
$ ls
calc_add.c calc_add.o
$ gcc -shared -o libmyapp.dylib calc_add.o 
$ ls
calc_add.c     calc_add.o     libmyapp.dylib
共有ライブラリをリンクする

myapp配下のソースをコンパイルして先ほど作成した
共有ライブラリをリンクします。

共有ライブラリはmyappの配下に移動した状態とします。

$ gcc -c main.c -I../include
$ ls
libmyapp.dylib main.c         main.o
$ gcc -o main main.o -I../include -L. -lmyapp 
$ ls
libmyapp.dylib main           main.c         main.o
$ ./main 
100 + 200 = 300


macの場合、共有ライブラリの標準的な配置場所は
/usr/local/libとなっています。
この場所に配置した場合は、-Lの指定は不要となります。

$ ls /usr/local/lib/libmyapp.dylib 
/usr/local/lib/libmyapp.dylib
$ gcc -o main main.o -I../include -lmyapp 
$ ls
main   main.c main.o
$ ./main 
100 + 200 = 300



以上です。

【C#】処理を待機する(Thread.Sleep、Task.Delay)

こんにちは。
本日はC#メモです。

Thread.Sleep()を使用した処理の待機

Thread.Sleep()は引数に指定した時間分処理を待機します。

Thread.Sleep(TimeSpan.FromMilliseconds(1000));


待機をキャンセルする

以下のようにキャンセルトークンを引数でもらい
都度監視するようにします。

public void Sample(int millsec, CancellationToken token)
{
    var cur = 0;
    var span = 50;

    try
    {
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] Start.");
        for (;;)
        {
            if (token.IsCancellationRequested)
            {
                return;
            }

            Thread.Sleep(TimeSpan.FromMilliseconds(span));
            cur += span;
            if (millsec <= cur)
            {
                return;
            }
        }
    }
    finally
    {
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] End.");
    }
}

呼び出し側は以下です。
待機時間には2秒を指定しますが、1秒待機後にキャンセルします。

var cts = new CancellationTokenSource();
var token = cts.Token;
var t = Task.Run(() => {
    this.Sample(2000, token);
});

Thread.Sleep(1000);
cts.Cancel();
t.Wait();

実行結果は以下です。
1秒後にキャンセルされて待機が終了しています。

[15:07:19.042] Start.
[15:07:20.054] End.


Task.Delay()を使用した処理の待機

Task.Delay()もThread.Sleep()と同様に
引数に指定した時間処理を待機します。
Task.Delay()は戻り値がTaskとなります。

var t = Task.Delay(TimeSpan.FromMilliseconds(1000));
t.Wait();


待機をキャンセルする

Task.Delay()は引数にキャンセルトークンを指定してキャンセルが可能です。

public void Sample(int millsec, CancellationToken token)
{
    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] Start.");
    Task.Delay(TimeSpan.FromMilliseconds(millsec), token);
    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] End.");
}

呼び出し側は以下です。
待機時間には2秒を指定しますが、1秒待機後にキャンセルします。

var cts = new CancellationTokenSource();
var token = cts.Token;
var t = Task.Run(() => {
    this.Sample(2000, token);
});

Thread.Sleep(1000);
cts.Cancel();
t.Wait();

実行結果は以下です。
1秒後にキャンセルされて待機が終了しています。

[15:23:27.888] Start.
[15:23:28.909] End.



以上です。

【C】[超入門] C言語でコンパイル

こんにちは。
本日はC言語メモです。

概要

C言語で開発を行う際、いつもコンパイルってどうするんだっけ??
ってなるので自分用メモです。

本記事では、
gccを使用したコンパイル方法について記載します。


.cファイルのみの場合

以下のようなディレクトリ階層とします。

app
  ┗ main.c

main.cファイルの内容は以下です。

#include <stdio.h>

int main() {

    printf("Hello World!\n");
    return 0;
}

こちらをコンパイルしましょう。
以下のコマンドを実行しましょう。

$ gcc -c main.c 

実行後は、main.cの他にmain.oが生成されます。

$ ls
main.c main.o

-c オプションを指定して実行すると、.cファイルをコンパイル
オブジェクトファイルを生成します。

次に、実行ファイルを作成します。
以下のコマンドを実行しましょう。

$ gcc -o main main.o

実行後は、mainというファイルが生成されています。

$ ls
main   main.c main.o

-o オプションを指定して実行すると、
実行ファイルを生成します。

生成されたmainを実行すると以下のようになります。

$ ./main 
Hello World!


.hファイルが存在する場合

先程の階層にヘッダファイル(.h)を追加します。

app
 ┣ main.h
 ┗ main.c

各ファイルの内容は以下です。

  • main.c
#include <stdio.h>
#include "main.h"

int main() {

    printf("My Name Is %s!\n", DEF_NAME);
    return 0;
}
  • main.h
#ifndef MAIN_H
#define MAIN_H

#define DEF_NAME   ("BOB")

#endif // MAIN_H

では、コンパイルしていきます。
今回のパターンの場合、main.cとmain.hが同一階層に存在するので
先ほどと同様にコンパイル~実行ファイル作成が可能です。

$ gcc -c main.c
$ ls
main.c main.h main.o
$ gcc -o main main.o
$ ls
main   main.c main.h main.o
$ ./main 
My Name Is BOB!


.hファイルが存在する場合(他の階層)

ヘッダファイルの位置を先程と異なる場所にします。

indlude
 ┗ main.h
app
 ┗ main.c

先ほどと同じようにコンパイルするとエラーとなります。

$ gcc -c main.c
main.c:2:10: fatal error: 'main.h' file not found
#include "main.h"
         ^~~~~~~~
1 error generated.

ヘッダファイルの場所を教えてあげる必要があります。
ヘッダファイルのパスを指定するには-Iオプションを使用します。
コンパイル後のコマンドは先程と同様です。

$ gcc -c main.c -I../include
$ ls
main.c main.o
$ gcc -o main main.o
$ ls
main   main.c main.o
$ ./main
My Name Is BOB!


複数のオブジェクトファイルから実行ファイルを生成

以下のディレクトリ構成で、main.cとsub.cから
mainという名前の実行ファイルを生成しましょう。

include
 ┣ main.h
 ┗ sub.h
app
 ┣ main.c
 ┗ sub.c

各ファイルの中身は以下です。

  • main.h
#ifndef MAIN_H
#define MAIN_H

#include "sub.h"

#define DEF_NAME   ("BOB")

#endif // MAIN_H
  • sub.h
#ifndef SUB_H
#define SUB_H

#define DEF_COLOR   ("Yellow")

int printColor();

#endif // SUB_H
  • main.c
#include <stdio.h>
#include "main.h"

int main() {

    printf("My Name Is %s!\n", DEF_NAME);
    printColor();
    return 0;
}
  • sub.c
#include <stdio.h>
#include "sub.h"

int printColor() {

    printf("My Color Is %s\n", DEF_COLOR);
    return 0;
}

コンパイルは先程と同様に
main.c、sub.cそれぞれに対して行います。
異なる部分は、実行ファイルを生成する際です。
今までのパターンでは、main.oのみを指定していましたが
今回は、sub.oも指定してあげます。

$ gcc -c main.c -I../include
$ ls
main.c main.o sub.c
$ gcc -c sub.c -I../include
$ ls
main.c main.o sub.c  sub.o
$ gcc -o main main.o sub.o
$ ls
main   main.c main.o sub.c  sub.o
$ ./main 
My Name Is BOB!
My Color Is Yellow



以上です。