POSIX関数S_ISDIRが時折私に嘘をつきます。
明らかにそうでない場合、ディレクトリが存在することを私に伝えています。S_ISDIR()は、ディレクトリが存在しないときにディレクトリを示す理由は何ですか?
$./main
-1 false
-1 false
-1 false
-1 false
-1 false
-1 false
$./main
-1 false
-1 false
-1 true
-1 true
-1 true
-1 true
$./main
-1 false
-1 false
-1 false
-1 false
-1 false
-1 false
:私は(多くの時間)は、このプログラムを実行する場合
#include <sys/stat.h>
#include <dirent.h>
#include <string>
#include <iostream>
#include <iomanip>
bool Is_Directory(const char* path_to_file){
struct stat fileInfo;
std::cout << lstat(path_to_file, &fileInfo) << " ";
return S_ISDIR(fileInfo.st_mode);
}
int main(){
std::cout << std::boolalpha;
std::cout << Is_Directory("folder") << '\n';
std::cout << Is_Directory("folder") << '\n';
std::cout << Is_Directory("folder") << '\n';
std::cout << Is_Directory("folder") << '\n';
std::cout << Is_Directory("folder") << '\n';
std::cout << Is_Directory("folder") << '\n';
}
は、非常に迅速に、私は次の出力が表示されます。ここでは
は、問題を説明する小さなプログラムですディレクトリが存在しない場合でも、関数が突然true
を返す方法を参照してください。
奇妙なことですが、プログラムを無限ループでチェックすると、ディレクトリが存在しないと言うことになります。プログラムを何度も繰り返し実行するだけで、問題が発生します。ここで
は、私がこれまで試したものです:
チェックコード: は、コードが間違っていないようです。
Macro: int S_ISDIR (mode_t m)
This macro returns non-zero if the file is a directory.
lstat
のエラーコードは常に-1ですので、私は時折エラー移入スタットはないと思います。私はlstat
にある以下のドキュメントを見 :
は、ドキュメントを読んで
lstat() is identical to stat(), except that if pathname is a symbolic
link, then it returns information about the link itself, not the file
that it refers to.
を私はまさにこのことの意味を理解していないが、多分それは私の問題に関連しますか?
代わりに普通のstat()
を使用することに決めましたが、私はまだ同じ問題を抱えています。
異なるコンパイラ: 私は警告とサニタイザで2種類のコンパイラを試しました。
g++
およびclang++
。どちらも同じ問題を呈します。
Cコンパイラでコンパイルする必要がありますか?
私はvanilla Cでプログラムを書き直しました(しかしg ++/clang ++でコンパイルしました)。
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
bool Is_Directory(const char* path_to_file){
struct stat fileInfo;
printf("%d ",lstat(path_to_file, &fileInfo));
return S_ISDIR(fileInfo.st_mode);
}
int main(){
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
}
突然のすべてが、問題がなくなっています。プログラムを何度も何度もやり直しますが、ディレクトリが存在しないことを常に正確に報告します。
私はC++コードに戻り、再度テストを実行します。確かに、時々間違った陽性。
システムヘッダですか?
私はC++ヘッダーをCバージョンに入れました。プログラムは問題なく動作します。
std :: coutですか?
std::cout
が遅いので、私はその問題を見ているのです...または、まったく無関係かもしれません。たぶんstd::cout
を使用していると間接的に問題の原因となっているバイナリに何かが残っています。または、std::cout
は私のプログラムの環境に対して何かを世界的に行っていますか?
ここでは暗闇の中で撮影しています。
私は次のことを試してみました:
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <iostream>
bool Is_Directory(const char* path_to_file){
struct stat fileInfo;
printf("%d ",lstat(path_to_file, &fileInfo));
return S_ISDIR(fileInfo.st_mode);
}
int main(){
std::cout << "test" << std::endl;
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
printf("%d\n",Is_Directory("folder"));
}
なるほど!
$./main
test
-1 0
-1 0
-1 0
-1 0
-1 0
-1 0
$./main
test
-1 0
-1 0
-1 0
-1 0
-1 0
-1 0
$./main
test
-1 1
-1 0
-1 0
-1 0
-1 0
-1 0
$./main
test
-1 0
-1 0
-1 0
-1 0
-1 0
-1 0
$./main
test
-1 1
-1 0
-1 0
-1 0
-1 0
-1 0
$./main
test
-1 0
-1 0
-1 0
-1 0
-1 0
-1 0
時には最初のチェックでtrueを返すことがあります。
S_ISDIR
のようなもので、S_ISDIR
が呼び出された後には、S_ISDIR
の次の呼び出しが混乱しないように、std::cout
のようなものです。
調査ソース:
私は/usr/include/sys
にS_ISDIR
のソースコードを発見した:
/* Test macros for file types. */
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
S_ISDIR
は、ヘルパーが、何もないように思われ、ディレクトリが存在するかどうか、すでにから決定されていますstat()
。 (繰り返しますが、私はstat
とlstat
の両方を試してみた。私は人々が私のコード例と同じように S_ISDIR
を使用しているオンラインの他の例を見つけた。私はそうは思いませんfstat
?を使用すると仮定アム)。
また、コードをチェックして印刷する無限ループにコードを入れても、std::cout
と表示されません。
$./main
-1 false
-1 false
-1 true
-1 true
-1 true
-1 true
オペレーティングシステムを/:あなたは私の元の出力を見れば、それは行っているので、問題はプログラムの開始時に発生するが、私はそれがいずれかの真実は思えない推測と信じて私につながりますハードドライブ/システムライブラリ/コンパイラ
私のコンピュータに問題がありますか? いいえ、私はUbuntu 16.04.1 LTS
です。私は行って、これを別のマシンCentOS 6.5
に入れて、より古いバージョンのg++
で試しました。同じ結果。
私のコードは悪いです。
は、問題を切り分け:
私は問題を単純化してきました。
このプログラムにはがあります。エラーを返します。
#include <sys/stat.h>
#include <iostream>
bool Is_Directory(const char* path_to_file){
struct stat fileInfo;
stat(path_to_file, &fileInfo);
return S_ISDIR(fileInfo.st_mode);
}
int main(){
std::cout << std::endl;
return Is_Directory("folder");
}
このプログラム意志決してリターンエラー。
#include <sys/stat.h>
#include <iostream>
bool Is_Directory(const char* path_to_file){
struct stat fileInfo;
stat(path_to_file, &fileInfo);
return S_ISDIR(fileInfo.st_mode);
}
int main(){
return Is_Directory("folder");
}
なぜバッファをフラッシュすると、ディレクトリが存在することがありますか?
実際には、バッファをフラッシュするだけで問題はなくなります。
このプログラム意志決してリターンエラー。
#include <sys/stat.h>
#include <iostream>
bool Is_Directory(const char* path_to_file){
struct stat fileInfo;
stat(path_to_file, &fileInfo);
return S_ISDIR(fileInfo.st_mode);
}
int main(){
std::cout.flush();
return Is_Directory("folder");
}
これはおそらく何もフラッシュしていないためです。
少なくとも1文字をフラッシュしている限り、私たちは再び問題を抱えています。ここ
は本当のMCVEです:
#include <sys/stat.h>
#include <iostream>
int main(){
std::cout << std::endl;
struct stat fileInfo;
stat("f", &fileInfo);
return S_ISDIR(fileInfo.st_mode);
}
ここでも、無限ループが動作しません。 (それが最初の試行での幸運を取得仮定)
このプログラムはなり決してリターン:プロセスと同様にフラッシュを再起動したときに
#include <sys/stat.h>
#include <iostream>
int main(){
while (true){
std::cout << std::endl;
struct stat fileInfo;
stat("f", &fileInfo);
if(S_ISDIR(fileInfo.st_mode)) return 0;
}
}
ので、問題が発生しますか?
私はアセンブリをダンプしましたが、それは私にはあまり意味がありません。
g++ -std=c++1z -g -c a.cpp
objdump -d -M intel -S a.o > a.s
a.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
#include <sys/stat.h>
#include <iostream>
int main(){
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: 48 81 ec a0 00 00 00 sub rsp,0xa0
b: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
12: 00 00
14: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
18: 31 c0 xor eax,eax
std::cout << std::endl;
1a: be 00 00 00 00 mov esi,0x0
1f: bf 00 00 00 00 mov edi,0x0
24: e8 00 00 00 00 call 29 <main+0x29>
struct stat fileInfo;
stat("f", &fileInfo);
29: 48 8d 85 60 ff ff ff lea rax,[rbp-0xa0]
30: 48 89 c6 mov rsi,rax
33: bf 00 00 00 00 mov edi,0x0
38: e8 00 00 00 00 call 3d <main+0x3d>
return S_ISDIR(fileInfo.st_mode);
3d: 8b 85 78 ff ff ff mov eax,DWORD PTR [rbp-0x88]
43: 25 00 f0 00 00 and eax,0xf000
48: 3d 00 40 00 00 cmp eax,0x4000
4d: 0f 94 c0 sete al
50: 0f b6 c0 movzx eax,al
53: 48 8b 55 f8 mov rdx,QWORD PTR [rbp-0x8]
57: 64 48 33 14 25 28 00 xor rdx,QWORD PTR fs:0x28
5e: 00 00
60: 74 05 je 67 <main+0x67>
62: e8 00 00 00 00 call 67 <main+0x67>
67: c9 leave
68: c3 ret
0000000000000069 <_Z41__static_initialization_and_destruction_0ii>:
69: 55 push rbp
6a: 48 89 e5 mov rbp,rsp
6d: 48 83 ec 10 sub rsp,0x10
71: 89 7d fc mov DWORD PTR [rbp-0x4],edi
74: 89 75 f8 mov DWORD PTR [rbp-0x8],esi
77: 83 7d fc 01 cmp DWORD PTR [rbp-0x4],0x1
7b: 75 27 jne a4 <_Z41__static_initialization_and_destruction_0ii+0x3b>
7d: 81 7d f8 ff ff 00 00 cmp DWORD PTR [rbp-0x8],0xffff
84: 75 1e jne a4 <_Z41__static_initialization_and_destruction_0ii+0x3b>
extern wostream wclog; /// Linked to standard error (buffered)
#endif
//@}
// For construction of filebuffers for cout, cin, cerr, clog et. al.
static ios_base::Init __ioinit;
86: bf 00 00 00 00 mov edi,0x0
8b: e8 00 00 00 00 call 90 <_Z41__static_initialization_and_destruction_0ii+0x27>
90: ba 00 00 00 00 mov edx,0x0
95: be 00 00 00 00 mov esi,0x0
9a: bf 00 00 00 00 mov edi,0x0
9f: e8 00 00 00 00 call a4 <_Z41__static_initialization_and_destruction_0ii+0x3b>
a4: 90 nop
a5: c9 leave
a6: c3 ret
00000000000000a7 <_GLOBAL__sub_I_main>:
a7: 55 push rbp
a8: 48 89 e5 mov rbp,rsp
ab: be ff ff 00 00 mov esi,0xffff
b0: bf 01 00 00 00 mov edi,0x1
b5: e8 af ff ff ff call 69 <_Z41__static_initialization_and_destruction_0ii>
ba: 5d pop rbp
bb: c3 ret
私はstatソースコードに従ってみましたが、やや失われました。
C++ソースコードのほうが少し面白かったです。
template<typename _CharT, typename _Traits>
basic_ostream<_CharT, _Traits>&
basic_ostream<_CharT, _Traits>::
flush()
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function?
// basic_ostream::flush() is *not* an unformatted output function.
ios_base::iostate __err = ios_base::goodbit;
__try
{
if (this->rdbuf() && this->rdbuf()->pubsync() == -1)
__err |= ios_base::badbit;
}
__catch(__cxxabiv1::__forced_unwind&)
{
this->_M_setstate(ios_base::badbit);
__throw_exception_again;
}
__catch(...)
{ this->_M_setstate(ios_base::badbit); }
if (__err)
this->setstate(__err);
return *this;
}
pubsync()
を呼び出すように思わ/ext/stdio_sync_filebuf.h
にsync()
方法に私を導く:ここ/bits/ostream.tcc
からフラッシュ機能がある
sync()
{ return std::fflush(_M_file); }
virtual std::streampos
seekoff(std::streamoff __off, std::ios_base::seekdir __dir,
std::ios_base::openmode = std::ios_base::in | std::ios_base::out)
{
std::streampos __ret(std::streamoff(-1));
int __whence;
if (__dir == std::ios_base::beg)
__whence = SEEK_SET;
else if (__dir == std::ios_base::cur)
__whence = SEEK_CUR;
else
__whence = SEEK_END;
#ifdef _GLIBCXX_USE_LFS
if (!fseeko64(_M_file, __off, __whence))
__ret = std::streampos(ftello64(_M_file));
#else
if (!fseek(_M_file, __off, __whence))
__ret = std::streampos(std::ftell(_M_file));
#endif
return __ret;
}
virtual std::streampos
seekpos(std::streampos __pos,
std::ios_base::openmode __mode =
std::ios_base::in | std::ios_base::out)
{ return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); }
}; sync()
{ return std::fflush(_M_file); }
virtual std::streampos
seekoff(std::streamoff __off, std::ios_base::seekdir __dir,
std::ios_base::openmode = std::ios_base::in | std::ios_base::out)
{
std::streampos __ret(std::streamoff(-1));
int __whence;
if (__dir == std::ios_base::beg)
__whence = SEEK_SET;
else if (__dir == std::ios_base::cur)
__whence = SEEK_CUR;
else
__whence = SEEK_END;
#ifdef _GLIBCXX_USE_LFS
if (!fseeko64(_M_file, __off, __whence))
__ret = std::streampos(ftello64(_M_file));
#else
if (!fseek(_M_file, __off, __whence))
__ret = std::streampos(std::ftell(_M_file));
#endif
return __ret;
}
virtual std::streampos
seekpos(std::streampos __pos,
std::ios_base::openmode __mode =
std::ios_base::in | std::ios_base::out)
{ return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); }
};
私の知る限り、C++が作業を行う農業れますstd::fflush
に
いくつかのより多くのテストを行った後、私は fflush()
<iostream>
から展示の問題が、<stdio.h>
からfflush()
がないことを発見しました。
私はfflush()
から後方にトレースしようとしましたが、私はソースコード境界に当たったと思います。
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int fflush (FILE *__stream);
__END_NAMESPACE_STD
#ifdef __USE_MISC
/* Faster versions when locking is not required.
This function is not part of POSIX and therefore no official
cancellation point. But due to similarity with an POSIX interface
or due to the implementation it is a cancellation point and
therefore not marked with __THROW. */
extern int fflush_unlocked (FILE *__stream);
#endif
これは私がリンクしているものである必要がありますか?
//exhibits the problem
#include <sys/stat.h>
#include <iostream>
int main(){
printf("\n");fflush(stdout);
struct stat fileInfo;
stat("f", &fileInfo);
return S_ISDIR(fileInfo.st_mode);
}
g++ -std=c++11 -o main a.cpp
ldd main
linux-vdso.so.1 => (0x00007ffdc878e000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1300c00000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1300837000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f130052d000)
/lib64/ld-linux-x86-64.so.2 (0x000055bace4bc000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1300316000)
//works correctly
#include <sys/stat.h>
#include <stdio.h>
int main(){
printf("\n");fflush(stdout);
struct stat fileInfo;
stat("f", &fileInfo);
return S_ISDIR(fileInfo.st_mode);
}
g++ -std=c++11 -o main a.cpp
ldd main
linux-vdso.so.1 => (0x00007ffd57f7c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f482dc6c000)
/lib64/ld-linux-x86-64.so.2 (0x000055828633a000)
私はlibstdc++.so.6
がS_ISDIR
を使用するのに適していないが、libc.so.6
があると仮定?別にS_ISDIR
を使用するコードを作成して、それをC++コードとリンクする必要がありますか?このような問題を早期に発見するにはどうしたらいいでしょうか?私はまだ何が起こっているのか分からない。私は間違ったライブラリをリンクしたため、間違ったメモリを踏みにじる/観察していますか?これを解決するにはどうしたらいいですか?
システムコールが成功した場合にのみ、 'lstat()'によって返されるモードを分析することができます。失敗した場合、 '-1'を返します(値は不定ですが、おそらく' fileInfo'のデータは変更されていません)。 'fileInfo.st_mode'で取得するのは、' lstat() 'が失敗したためにガベージです。' S_ISDIR() 'が真偽でtrueまたはfalseを返すことができます。 –
'lstat'が-1を返した場合、初期化されていない' struct stat'に対して 'S_ISDIR'を実行しています。 –
_ "lstatのエラーコードは常に-1なので、時折エラーが発生しているとは思われません。" –