質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

5回答

2115閲覧

PythonからCのscanf()にデータを送りたい

skru

総合スコア1

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2021/05/21 05:11

編集2021/05/21 07:14

C言語で、次のプログラムのscanf()に、pythonのプログラムからデータを送りたいです。

C

1#include <stdio.h> 2 3void input() 4{ 5 char input[100] = ""; 6 printf("input\n"); 7 scanf("%s", input); 8 printf("%s\n", input); 9} 10 11int main() 12{ 13 input(); 14 return 0; 15}

pythonではファイルから読み込んだデータをCのプログラムに渡したいです。

python

1with open('datas1', 'rb') as f: 2 datas = f.read() 3with open('datas2', 'rb') as f: 4 datas2 = f.read() 5 6datas += datas2

この変数datasの値を、Cのscanf()に渡したいのですが、どうすればよいでしょうか

追記
Cのプログラムは起動していて、scanf()の部分で入力待ちになっている状態です。

追記2
C側のプログラムは変更できないです。

追記3
環境はUbuntu 16.04 32bitです

追記4
以下のコードを試したのですが、失敗しました(./targetはcをコンパイルした実行ファイルです)

python

1p = subprocess.Popen(['./target'], stdout=subprocess.PIPE, stdin=subprocess.PIPE) 2msg = p.stdout.readline() 3print(msg) 4p.stdin.write(datas)

プロセスの起動は確認しました。

$ ps aux | grep target user 6406 0.0 0.0 2208 532 pts/19 S+ 16:09 0:00 ./target

しかし、起動してもreadline()が実行されず、ずっと待ち状態になります。
改善点がありましたら、ご教授ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/05/21 06:27

実行環境(OS等)は何でしょう。Linuxでしょうか。
skru

2021/05/21 06:39

Ubuntu 16.04 32bitです
tatsu99

2021/05/21 09:58

pythonのスクリプトで、datas1,datas2をバイナリモードで読み込んでますが、データは文字列ではないのでしょうか。なぜ、テキストモードで読み込まないのでしょうか。
otn

2021/05/21 14:50

> 追記1 > Cのプログラムは起動していて、scanf()の部分で入力待ちになっている状態です。 と書いてありますが、 > 追記4 > 以下のコードを試したのですが、 のコードを見ると、PythonからCのプログラムを起動しています。 Pythonプログラム起動前からCのプログラムは動いているのか、PythonプログラムkらCプログラムを起動するのか、やりたいことはどちらなのでしょうか?
skru

2021/05/21 15:10

やりたいことは、"Pythonプログラム起動前からCのプログラムは動いている"状態です。 他の方の回答でPIPEを使うようにと言われて、PIPEを調べたのですが、Popen()で標準入出力を指定する方法しか見つからなかったので、仕方なくpythonからCプログラムを起動しました。 Cのプログラムは動いている状態から、PIPEを使ってscanf()に入力する方法があれば、教えていただきたいです。
otn

2021/05/21 16:38

稼働中のプログラムを何とかするには、gdbなどで接続して標準入力をつなぎ替えるなどでしょうか。あまり詳しく知らないので具体的には書けませんが。
dodox86

2021/05/21 18:24

> gdbなどで接続して標準入力をつなぎ替える CTFの問題と言うことで、実はこれが解答のひとつな気がします。なんとなくですが。
otn

2021/05/21 22:21

標準入力を名前付きパイプにリダイレクトして、Pythonから名前付きパイプに書き込めばいいかと思ったのですが、gdbの操作が悪いのか、close(0) と open("/tmpo/xx",0)でリダイレクトできたものの、プログラムが読んでくれない。
guest

回答5

0

ベストアンサー

質問へのコメントに書いた下記ですが、

標準入力を名前付きパイプにリダイレクトして、Pythonから名前付きパイプに書き込めばいいかと思ったのですが、gdbの操作が悪いのか、close(0) と open("/tmpo/xx",0)でリダイレクトできたものの、プログラムが読んでくれない。

なんかやり直すとうまく行きました。
端末3つ使います。

端末1で、プログラム起動。

端末2で、

sh

1$ mkfifo /tmp/foo 2$ gdb プログラムファイル プロセスID 3GNU gdb (GDB) Red Hat Enterprise Linux 8.2-12.el8 4~~~(中略) 5(gdb) p (int)close(0) 6$1 = 0 7(gdb) p (int)open("/tmp/foo",0) ← ここでブロックされるので、 8$2 = 0 9(gdb) detach 10(gdb) quit

上記openの時にopenがすぐに完了せずに待ちになっている模様で、gdbプロンプトがでない。
端末3で、

sh

1echo 123 > /tmp/foo

とやると、端末2がopenから復帰。
detachすると、端末1に123の出力が出ている。

もう一度やり直して、openの前にecho 123 > /tmp/fooしておくと、今度はopenがすぐ完了しました。

このgdbへのコマンド投入操作をPythonからsubporcessを使って行えば良いかと思います。

投稿2021/05/21 22:46

編集2021/05/21 23:30
otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skru

2021/05/22 03:43

回答していただきありがとうございます。 質問が2つございまして、 1, echo 123 > /tmp/foo は pythonのスクリプトに置き換えれば良いでしょうか? 2, コマンド投入操作をsubprocessで行うにはどうすればよいでしょうか 重ねての質問となってしまいますが、どうかお願いいたします。
otn

2021/05/22 04:25

1.そうですね。普通に名前付きパイプをオープンしてwriteすればいいです。 2.はsubprocesを使います。簡単には、 subprocess.run("gdb xxxx 9999", input=b''' p (int)close(0) p (int)open("/tmp/foo",0) p detach quit ''',shell=True) 回答に書いたとおり、ブロックされるのでスレッドを生成して別スレッドで実行する必要があると思います。
skru

2021/05/22 04:28

詳しく解説してくださり、本当にありがとうございました!
guest

0

注意 - 以下の内容は回答として間違いです。質問の課題を解決できるものではありません。[2021/05/22 13:07追記]
(話の経緯を明確にするため、そのまま残しています。詳細は本回答コメント欄をご覧ください)


C言語で、次のプログラムのscanf()に、pythonのプログラムからデータを送りたいです。

Linuxのprocファイルシステムを使ってデータを送る例をご案内します。(Ubuntu16.04 64ビットで確認)

Linuxには、procファイルシステムがあり、各プロセスが開いているファイルディスクリプターを外部から扱うことができます。C言語で書かれたプログラムがscanfで普通に入力待ちをしているとき、そのファイルディスクリプターは標準入力(STDIN)の0です。procファイルシステムではこれが仮想的なファイルになります。これへのリダイレクトで外部からのデータを当該プロセスへ流し込むことができます。

例えばプロセスID 123のプロセスであれば、その標準入力のファイルディスクリプターはprocファイルシステム下においてファイル名「/proc/123/fd/0」となります。ちょっとばかり実演してみましょう。

※この例ではC言語側のソースファイルを、プロセスIDが分かり易いようにgetpid()で得たプロセスIDを出力するよう、修正しています。

C

1#include <stdio.h> 2 3#include <sys/types.h> 4#include <unistd.h> 5 6void input() 7{ 8 printf("pid=%u\n", getpid()); 9 char input[100] = ""; 10 printf("input\n"); 11 scanf("%s", input); 12 printf("%s\n", input); 13} 14 15int main() 16{ 17 input(); 18 return 0; 19}

これを実行し、起動したままとします。本例ではプロセスID 3181です。

bash

1user01@ubuntu1604-x64:~$ gcc -Wall t1.c 2user01@ubuntu1604-x64:~$ ./a.out 3pid=3181 4input

これに対して、別の端末から標準入力(要はscanfの入力)へデータを流し込んでみます。echoコマンドのリダイレクトで充分です。

bash

1user01@ubuntu1604-x64:~$ echo "12345" > /proc/3181/fd/0

すると、scanfで入力待ちしている方の端末で12345が出力されることが確認できると思います。

更に今回はPython3スクリプトからと言うことなのでそれを利用してみます。ファイルのデータを使うので、本例ではdecodeします。

Python3

1user01@ubuntu1604-x64:~$ cat t1.py 2with open('datas1', 'rb') as f: 3 datas = f.read() 4with open('datas2', 'rb') as f: 5 datas2 = f.read() 6 7datas += datas2 8 9print(datas.decode(encoding='utf-8'))

このPython3スクリプトをt1.py として実行します。

bash

1user01@ubuntu1604-x64:~$ cat datas1 2text in datas1 3user01@ubuntu1604-x64:~$ cat datas2 4text in datas2 5user01@ubuntu1604-x64:~$ python3 t1.py 6text in datas1 7text in datas2 8 9user01@ubuntu1604-x64:~$

で、このPython3スクリプトの出力結果をechoでの例と同様に/proc/3181/fd/0/にリダイレクトすれば、scanfで入力待機している端末にやはり出力されます。

bash

1user01@ubuntu1604-x64:~$ python3 t1.py > /proc/3181/fd/0

一応この方法ならば、C言語側プログラムは普通に起動したままで外部からデータを流し込むことができます。お試しください。

投稿2021/05/21 08:33

編集2021/05/22 04:07
dodox86

総合スコア9256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skru

2021/05/21 08:55

ご丁寧にありがとうございます! そんな方法があったとは知りませんでした。大変勉強になります。 この方法だと困ったことがございまして、 1, python3 helloworld.py > /proc/2210/fd/0 でHello World!と出力してみたのですが、 pid=2210 input user@ubuntu-x86:~/test$ Hello World! と不要なuser名まで出力されてしまいます。 user名を消すにはどうすればよいでしょうか
dodox86

2021/05/21 09:37

妙ですね。こちらではsshでログインした端末、Ubuntu16のUnityの端末それぞれで試しましたが、余分なユーザー名が出るようなことは無かったのですが。 > user@ubuntu-x86:~/test$ Hello World! これは、単にシェルのプロンプト表示とC言語プログラム起動時のコマンドラインではないのですか?
dodox86

2021/05/21 09:42

何となく、変なPython3スクリプト側からエスケープシーケンスを出力してしまっていて、端末上の表示順が乱れてしまっているようにも思いますが。helloworld.py を使わず、 echo "Hello" > /proc/2210/fd/0 などと実行してみても、同じようにダメでしょうか。
skru

2021/05/21 12:42

返信遅くなりすいません。 echo "Hello" > /proc/2210/fd/0 でもおなじようにユーザー名まで出力されてしまいます。
dodox86

2021/05/21 13:14

うーん何でしょう。お使いの環境特有の動作かな。
dodox86

2021/05/21 13:21

あ、いえ、違いますね。C言語のプログラムの方を見ると、input()関数で、1行のデータ入力でプログラムが終わるはずです。つまり、プログラムが終わり、シェルのプロンプトが表示されている状態です。であれば正しい動作です。むしろ、私の方でプログラムが終わっていないのが妙です。
otn

2021/05/21 15:37

/proc/$PID/fd/0 は、そのプロセスのFD0番がオープンしているファイルへのシンボリックリンクなので、そのプロセスを起動した端末に対して、echoをリダイレクトしているだけです。 echo Hello > /dev/pts/1 みたいな。
dodox86

2021/05/21 18:21

@otnさん コメントいただき、どうもありがとうございます。確認しました。 以下の例のように、確かにご指摘のとおり、リダイレクト結果が端末に出力されているだけで、C言語プログラムのscanfの入力には至っていませんでした。 ls -l /proc/4825/fd 合計 0 lrwx------ 1 user01 user01 64 5月 22 02:58 0 -> /dev/pts/0 lrwx------ 1 user01 user01 64 5月 22 02:59 1 -> /dev/pts/0 lrwx------ 1 user01 user01 64 5月 22 02:59 2 -> /dev/pts/0 これだと私の回答自体、不適切でNGですね。(質問者skruさんの場合でユーザー名がおまけで出力されているのが妙ですが、何らかのセキュリティ上のオプション出力なのかな?)
dodox86

2021/05/21 18:59 編集

質問者さんの環境での実行例で、実際にscanfへの入力になっていない(C言語プログラムが終わらない)のであれば、本回答に対する高評価は取り下げていただきたく思います。 前提条件を理解した上での回答だったので「低評価」もやむなし、です。
dodox86

2021/05/21 18:35

※試行・確認内容を参考のために追記: ダメ元で標準関数scanf()での入力ではなく、read(0, buf, sizeof(buf))のシステムコールでも試した。当然同じようにNG。
otn

2021/05/22 03:58

回答の冒頭に間違いである旨を書いておいて下さい。
dodox86

2021/05/22 04:08

otnさん、ご指摘どうもありがとうございます。その旨を追記しました。
guest

0

pythonの実行結果をパイプでC側に渡す方法です。
テキストモードでオープンするように変えました。

python

1 2with open('datas1', 'r') as f: 3 datas = f.read() 4with open('datas2', 'r') as f: 5 datas2 = f.read() 6 7datas += datas2 8 9print(datas,end="") 10

datas1の内容:12345
datas2の内容:6789

実行コマンド
python3 test.py | tera

test.pyは上記のpythonのスクリプトのファイル名
teraはC言語の実行モジュールのファイル名

実行結果
input
123456789

投稿2021/05/21 10:10

編集2021/05/21 10:11
tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/05/21 10:14 編集

C言語側プログラム、本回答で言うところのteraは、Python3スクリプトを実行する前からあらかじめ起動済みで、scanfによる入力待ちと言う条件だと思います。
tatsu99

2021/05/21 11:59

ご指摘ありがとうございます。その条件だと、回答として不適切ですね。本回答は、取り下げます。
guest

0

公式ドキュメントのsubprocess --- サブプロセス管理をお読みくだい。

投稿2021/05/21 05:48

ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skru

2021/05/21 06:12

ありがとうございます。 pythonからサブプロセスを起動する方法は分かったのですが、現在実行中のプロセスにアタッチする方法はないでしょうか?
ppaul

2021/05/21 06:28

アタッチしなくても、パイプを通して相手先のstdinに送れば良いと思います。
skru

2021/05/21 07:13

ありがとうございます。 Popenからstdin, stdoutを指定して実行してみたのですが、うまくいきません。 改善点を教えていただけないでしょうか
guest

0

こんにちは。

問題文読ませていただきました。

  1. c言語からpython呼び出し。
  2. pythonのres返す。
  3. c言語で受け取る。

が良さそうです。Python.hという、ライブラリがあるみたいですので、そちらを活用するとうまくいきそうです。

こちら参考になります。ご確認のほど、よろしくお願いいたします。????‍♂️
https://qiita.com/BabyJiG/items/9975195565df74debf6c

投稿2021/05/21 05:23

編集2021/05/21 05:23
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skru

2021/05/21 05:28

ありがとうございます。 お返事いただいたところ申し訳ないのですが、実はこれCTFの問題でして、C側のプログラムを変更することができない状態です。 変更できるのはpythonの方だけです。 なにか解決策はないでしょうか。
退会済みユーザー

退会済みユーザー

2021/05/21 05:57

あ、理解しました。ppaulさんのリンクが参考になりますので、ご確認のほどよろしくお願いいたします。????‍♂️
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問