Cで実行可能ファイルの場所を見つける方法は? の解決策として使用されるreadlink関数を使用して、char配列へのパスを取得するにはどうすればよいですか?また、変数bufおよびbufsizeは何を表し、それらをどのように初期化するのですか?
編集:上記の質問のように、現在実行中のプログラムのパスを取得しようとしています。その質問への答えはreadlink("proc/self/exe")
を使用すると述べました。それを自分のプログラムに実装する方法がわかりません。私は試した:
char buf[1024];
string var = readlink("/proc/self/exe", buf, bufsize);
これは明らかに正しくありません。
これ readlink()関数を適切に使用readlink
関数の正しい使用法。
std::string
にパスがある場合、次のようなことができます:
#include <unistd.h>
#include <limits.h>
std::string do_readlink(std::string const& path) {
char buff[PATH_MAX];
ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
if (len != -1) {
buff[len] = '\0';
return std::string(buff);
}
/* handle error condition */
}
固定パスの後だけの場合:
std::string get_selfpath() {
char buff[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
if (len != -1) {
buff[len] = '\0';
return std::string(buff);
}
/* handle error condition */
}
それを使用するには:
int main()
{
std::string selfpath = get_selfpath();
std::cout << selfpath << std::endl;
return 0;
}
manpage の内容を見てみましょう。
readlink() places the contents of the symbolic link path in the buffer
buf, which has size bufsiz. readlink does not append a NUL character to
buf.
OK。十分にシンプルでなければなりません。 1024文字のバッファがあるとします。
char buf[1024];
/* The manpage says it won't null terminate. Let's zero the buffer. */
memset(buf, 0, sizeof(buf));
/* Note we use sizeof(buf)-1 since we may need an extra char for NUL. */
if (readlink("/proc/self/exe", buf, sizeof(buf)-1) < 0)
{
/* There was an error... Perhaps the path does not exist
* or the buffer is not big enough. errno has the details. */
perror("readlink");
return -1;
}
受け入れられた答えはほぼ正しいです。ただし、PATH_MAXは信頼できないためです。
システムにそのような制限がない場合、POSIXごとに定義される保証はありません。
(readlink(2)マンページから)
また、定義されている場合、必ずしも「真の」制限を表すとは限りません。 ( http://insanecoding.blogspot.fr/2007/11/pathmax-simply-isnt.html を参照)
Readlinkのマンページもsymlinkでそれを行う方法を提供します:
静的なサイズのバッファを使用すると、シンボリックリンクのコンテンツに十分なスペースが提供されない場合があります。バッファーに必要なサイズは、リンク上のlstat(2)の呼び出しによって返されるstat.st_size値から取得できます。ただし、readlink()およびread- linkat()によって書き込まれたバイト数をチェックして、シンボリックリンクのサイズが呼び出し間で増加していないことを確認する必要があります。
ただし、/ proc/self/exe /の場合、ほとんどの/ procファイルの場合、stat.st_sizeは0になります。残っている唯一の解決策は、バッファが収まらないときにバッファのサイズを変更することです。
この目的のために、次のようにvector<char>
を使用することをお勧めします。
std::string get_selfpath()
{
std::vector<char> buf(400);
ssize_t len;
do
{
buf.resize(buf.size() + 100);
len = ::readlink("/proc/self/exe", &(buf[0]), buf.size());
} while (buf.size() == len);
if (len > 0)
{
buf[len] = '\0';
return (std::string(&(buf[0])));
}
/* handle error */
return "";
}
char *
readlink_malloc (const char *filename)
{
int size = 100;
char *buffer = NULL;
while (1)
{
buffer = (char *) xrealloc (buffer, size);
int nchars = readlink (filename, buffer, size);
if (nchars < 0)
{
free (buffer);
return NULL;
}
if (nchars < size)
return buffer;
size *= 2;
}
}
_#include <stdlib.h>
#include <unistd.h>
static char *exename(void)
{
char *buf;
char *newbuf;
size_t cap;
ssize_t len;
buf = NULL;
for (cap = 64; cap <= 16384; cap *= 2) {
newbuf = realloc(buf, cap);
if (newbuf == NULL) {
break;
}
buf = newbuf;
len = readlink("/proc/self/exe", buf, cap);
if (len < 0) {
break;
}
if ((size_t)len < cap) {
buf[len] = 0;
return buf;
}
}
free(buf);
return NULL;
}
#include <stdio.h>
int main(void)
{
char *e = exename();
printf("%s\n", e ? e : "unknown");
free(e);
return 0;
}
_
これは、伝統的な「適切なバッファーサイズがわからない場合は、2の累乗で再割り当てする」というトリックを使用しています。パス名に64バイト未満を割り当てることは、努力する価値がないと想定します。また、16384(2 ** 14)バイトの実行可能パス名は、プログラムのインストール方法になんらかの異常があることを示している必要があると想定しています。パス名を知っておくと、すぐに大きな問題が発生するため、心配する必要はありません。約。
_PATH_MAX
_のような定数を気にする必要はありません。非常に多くのメモリを予約することは、ほとんどすべてのパス名にとって過剰であり、別の回答で述べられているように、いずれにしても実際の上限であるとは限りません。このアプリケーションでは、16384などの常識的な上限を選択できます。常識的な上限がないアプリケーションでも、2の累乗の増加を再割り当てすることは良いアプローチです。 n
バイトの結果には_log n
_呼び出しのみが必要であり、浪費するメモリ容量は結果の長さに比例します。また、文字列の長さがrealloc()
とreadlink()
の間で変化する競合状態も回避します。