メモめもメモ

環境構築やプログラミングに関するメモ

C言語で文字列を逆順にするプログラム

C言語入門の宿題としてたまに見かけるお題です。

文字列の先頭と末尾から順に入れ替えを行っていきます。 下記のコードでは文字の入れ替えに排他的論理和演算を使っていますが、 char tmp; tmp = msg[i]; msg[i] = msg[len-1-i]; msg[len-1-i] = tmp;のように一時記憶領域を用意する方法のほうがわかりやすいです。

コード

#include <stdio.h>
#include <string.h>

// 入力文字列の最大長
#define MAXSIZE (256)

// 文字列msgを逆順にする関数
void reverse(char *msg, size_t maxsize)
{
    size_t i;
    size_t len = strnlen_s(msg, maxsize);

    for (i = 0; i < len / 2; i++)
    {
        msg[i] ^= msg[len - 1 - i];
        msg[len - 1 - i] ^= msg[i];
        msg[i] ^= msg[len - 1 - i];
    }
}

// 使用例
int main(void)
{
    char buf[MAXSIZE];

    printf("入力してください(%d文字まで): ", MAXSIZE);
    scanf_s("%s", buf, MAXSIZE);

    printf("入力した文字列: %s\n", buf);
    // 【出力例】入力した文字列: ABCDEFG

    reverse(buf, MAXSIZE);

    printf("反転した文字列: %s\n", buf);
    // 【出力例】反転した文字列: GFEDCBA

    return 0;
}

rdtsc命令とcpuid命令を使ったVM検知

cpuid命令をVM(Virtual Machine, 仮想マシン)環境で実行すると制御が一時的にVMM(Virtual Machine Monitor, 仮想マシンモニター)へ移るので、 物理マシン環境と比べて実行速度が遅くなります。 そのため、cpuid命令の実行速度をrdtsc命令などで計測することでVM検知を行うことができます。

コード(Visual C++用)

#include <stdio.h>

// VMならば1, そうでないならば0を返す
int cpuid_tsc_check()
{
    unsigned __int64 threshold = 750;

    unsigned __int64 i, loop = 10;
    unsigned __int64 avg, sum = 0;
    unsigned __int64 start, end;
    unsigned __int32 eax1, eax2, edx1, edx2;

    for (i = 0; i < loop; i++)
    {
        __asm {
            rdtsc;
            mov eax1, eax;
            mov edx1, edx;
        }
        start = ((unsigned __int64)edx1 << 32) | eax1;

        __asm {
            xor eax, eax;
            cpuid;
            rdtsc;
            mov eax2, eax;
            mov edx2, edx;
        }
        end = ((unsigned __int64)edx2 << 32) | eax2;

        sum += end - start;
    }
    
    avg = sum / loop;
    return avg > threshold ? 1 : 0;
}

// 使用例
int main(void)
{
    if (cpuid_tsc_check())
    {
        printf("このマシンはVMです。\n");
    }
    else
    {
        printf("このマシンはVMではありません。\n");
    }
    
    return 0;
}

Python3でISO 8601形式の時刻を取得する

現在のローカル時刻をタイムゾーン付きのISO 8601形式(YYYY-MM-DDThh:mm:ss±hh:mm)で取得します。 Python3.6からはnaiveなdatetimeオブジェクトもastimezone()を使えるようになりました。

import datetime

# --- python3.3以降 ---
utctime = datetime.datetime.now(datetime.timezone.utc) # awareな現在UTC時刻を取得
print(utctime.astimezone().isoformat()) # マイクロ秒有り
# 実行結果:2018-01-05T00:06:32.095958+09:00
print(utctime.replace(microsecond=0).astimezone().isoformat()) # マイクロ秒無し
# 実行結果:2018-01-05T00:06:32+09:00


# --- python3.6以降 ---
localtime = datetime.datetime.now() # naiveな現在ローカル時刻を取得
print(localtime.astimezone().isoformat()) # マイクロ秒有り
# 実行結果:2018-01-05T00:06:32.096458+09:00
print(localtime.replace(microsecond=0).astimezone().isoformat()) # マイクロ秒無し
# 実行結果:2018-01-05T00:06:32+09:00

Python3.6でランダムなパスワードを生成する

Python3.6で実装されたsecretモジュールを使うと、暗号学的に強い乱数を簡単に得ることができます。 これを使ってランダムなパスワードを生成することができます。

import secrets
import string

# パスワードの文字数
num = 16

# パスワードに使用する文字の候補
# 下記の場合、poolにはアルファベット小文字大文字 + 数字 + 記号が格納される
pool  = string.ascii_letters + string.digits + string.punctuation

# 候補からランダムに組み合わせてパスワードを生成する(復元抽出)
password = "".join([secrets.choice(pool) for i in range(num)])

# 生成したパスワードを出力
print(password)

# 出力例:
# Mf[WalgJ?`d7gF/'
# bT,q*~VsDqEk9d>G
# など

string.punctuationは文字列!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~を表しています。 パスワードに使えない文字が含まれている場合は、適宜別の文字列に置き換えるとよいでしょう。

認証プロキシ環境でpythonのRequestsライブラリを使用する方法

proxies引数を使おう

ユーザIDがusername、 パスワードがpassword、 プロキシのアドレスがhogehoge.proxy.jp、 プロキシのポート番号が8080 である場合は、

import requests

proxy_dict = {
    "http": "http://username:password@hogehoge.proxy.jp:8080/",
    "https": "http://username:password@hogehoge.proxy.jp:8080/"
}

req = requests.get("http://yahoo.co.jp/", proxies=proxy_dict)

とする。

認証プロキシ環境でpip installを使用する方法

--proxyオプションを使おう

インストール対象がfugafuga、 ユーザIDがusername、 パスワードがpassword、 プロキシのアドレスがhogehoge.proxy.jp、 プロキシのポート番号が8080 である場合は、

$ pip install fugafuga --proxy=http://username:password@hogehoge.proxy.jp:8080/

とする。

認証プロキシ環境でapt-getを使用する方法

まずは設定ファイルをエディタで開く

エディタはなんでもいいので、下記のどちらでもOK。

  • viを使いたい場合(viは大抵のlinuxで使える)
$ sudo vi /etc/apt/apt.conf
  • nanoを使いたい場合(Ubuntu系ならこちらのほうがわかりやすい)
$ sudo nano /etc/apt/apt.conf

設定ファイルに認証プロキシ設定を書き込む

ユーザIDがusername、 パスワードがpassword、 プロキシのアドレスがhogehoge.proxy.jp、 プロキシのポート番号が8080 である場合は、 先ほど開いた設定ファイルに

Acquire {
    http::proxy "http://username:password@hogehoge.proxy.jp:8080/";
}

と書き込み、保存して閉じる。

確認

$ sudo apt-get update

が通れば成功