LoginSignup
0
0

More than 5 years have passed since last update.

プログラミング言語Goを読みながらメモ(第十三章)

Posted at

プログラミング言語 Go を読みながらメモ。

第一章 : https://qiita.com/Nabetani/items/077c6b4d3d1ce0a2c3fd
第二章 : https://qiita.com/Nabetani/items/d053304698dfa3601116
第三章 : https://qiita.com/Nabetani/items/2fd9c372fcd8383955a5
第四章 : https://qiita.com/Nabetani/items/59bfd00dc3323883a07f
第五章 : https://qiita.com/Nabetani/items/4b785f1c9b0b26d48475
第六章 : https://qiita.com/Nabetani/items/1c100394a65af6506187
第七章 : https://qiita.com/Nabetani/items/6553ad253af77661e915
第八章 : https://qiita.com/Nabetani/items/3b2e3964159cc292fe00
第九章 : https://qiita.com/Nabetani/items/c94e51aa29926a56159e
第十章と第十一章は省略。
第十二章 : https://qiita.com/Nabetani/items/2d63279465e7ab8c20a2

で。

十三章は、楽しい unsafe。

ポインタを使ってプライベートメンバを書き換える

まずはこんなイタズラから。

go
package main

import (
    "fmt"
    "os"
    "reflect"
    "unsafe"
)

func main() {
    stdout := os.Stdout
    vs := reflect.ValueOf(stdout).Elem()
    file := vs.FieldByName("file")
    pfd := file.Elem().FieldByName("pfd")
    sysfd := pfd.FieldByName("Sysfd")
    unsafePtrToFD := unsafe.Pointer(sysfd.Addr().Pointer())
    intPtrToFD := (*int)(unsafePtrToFD)
    fmt.Fprintln(stdout, "stdout?") // 標準出力に出る
    *intPtrToFD = 2
    fmt.Fprintln(stdout, "stderr?") // 標準エラーに出る!
}

本当にこれで「stderr?」は標準エラーに出た。

unsafe.Pointer を使わないバージョンでは書き換え禁止だったけど、unsafe.Pointer を使ったら書き換えられた。素晴らしい。

とにかく、邪悪な用途に使えることはわかった。面白い。

cgo で、C のコードを呼ぶ

本よりも
http://otiai10.hatenablog.com/entry/2014/06/24/082448
が参考になった。

go
package main

/*
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char const * gcc_version(){
    static char r[] = "123.123.123";
    sprintf( r, "%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ );
    return r;
}

char const * clang_version(){
    return __clang_version__;
}

int is_cpp(){
#if defined __cplusplus
    return 1;
#else
    return 0;
#endif
}

*/
import "C"
import "fmt"

func main() {
    gv := C.gcc_version()
    fmt.Printf("gcc_version : %v\n", C.GoString(gv))
    //=> gcc_version : 4.2.1
    cv := C.clang_version()
    fmt.Printf("clang versoin : %v\n", C.GoString(cv))
    //=> clang versoin : 9.1.0 (clang-902.0.39.1)
    fmt.Printf("is_cpp() == %v\n", C.is_cpp())
    //=> is_cpp() == 0
}

こんな感じ。

cgo で、C++ のコードを呼ぶ

C++ を go のソースに埋め込む方法はわからなかったので、別ファイルにした。

まずは C++

c++
// clang++ -c hoge.cpp -o hoge.o

extern "C"
int is_cpp(){
#if defined __cplusplus
  return 1;
#else
  return 0;
#endif
}

を、コメントのとおりにビルドしておいて、
go にリンクする。

go
package main

/*
#cgo CFLAGS:
#cgo LDFLAGS: hoge.o

int is_cpp();

*/
import "C"
import "fmt"

func main() {
    fmt.Printf("is_cpp() == %v\n", C.is_cpp())
}

と、ちゃんと C++ のコードが呼べる。

終りに

というわけで、読破した。
読破しただけなので、練習問題もやっていないし、まだ書けるという感じではない。
とはいえ、全体像はわかったような気になった。

本の評価はあんまり高くないんだけど、これより良い本があるような気もしないので仕方ないという感じ。

C++でいうところの「注解C++リファレンスマニュアル」、あるいは C でいうところの「S・P・ハービソン3世とG・L・スティール・ジュニアのCリファレンスマニュアル」のような本がほしい。
まあウェブを見ろということなんだと思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0