I'm trying to compile this code, which works fine on Windows, on Linux (Code::Blocks):
/* Edit: Includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <...>
/**/
/* === */
/* Function code */
DIR *dp;
dirent *ep;
string name_parent;
dp = opendir(somepath);
name_parent = dp->dd_name; //error
/**/
Since path names on Windows are not case sensitive, I can read a user input like "c://program files" and get the "correct" path "C:\Program Files*" (except for the asterisk - or "F://" -> "F:*"). I also use this variable to get a directory listing with absolute path values, since ep->d_name (after some readdir() of course) returns a path relative to somepath.
On Linux, I get a compiler error (for "dp->dd_name"):
error: invalid use of incomplete type 'DIR'
Did I forget something?
Or is there a logical error?
Edit: I've added the includes (that I'm already using) above.
/* Edit: Includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <...>
/**/
/* === */
/* Function code */
DIR *dp;
dirent *ep;
string name_parent;
dp = opendir(somepath);
ep = readdir(dp);
name_parent = ep->d_name;
/**/
The variable d_name exists in the struct dirent which gives the name of the directory
You didn't declare the type of DIR! On Posix systems, you would have said,
#include <sys/types.h>
#include <dirent.h>
However, on Windows, you don't have these features. Instead, you could use the Windows API filesystem functions.
yes. you missed including header files.
dirent.h
The internal structure of a DIR is unspecified, so you should never rely on it and expect your code to be portable.
The glib source for Windows says this about DIR:
/*
* This is an internal data structure. Good programmers will not use it
* except as an argument to one of the functions below.
Apparently, the type DIR is not defined at the point you're trying to use it. Maybe you forgot an #include?
It is not about to forget including some headers or definition now I've faced this problem but not error it was warning.
My files.h;
class Files
{
public:
explicit Files(const char *p_path = 0);
~Files();
/* .... */
private:
std::string path;
}
My files.cpp;
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h> // I added this line with #Kerrek SB's advice but nothing changed
#include <dirent.h>
#include <files.h>
static DIR *p_dir = NULL;
static struct dirent *p_ent = NULL;
Files::Files(const char *p_path)
{
if (p_path == NULL)
{
std::cerr << "PATH is NULL" << std::endl;
exit(EXIT_FAILURE);
}
path = p_path;
p_dir = opendir(p_path);
if (p_dir == NULL)
{
std::cerr << "Cannot open " << path << std::endl;
exit(EXIT_FAILURE);
}
}
Files::~Files()
{
if (p_dir)
{
/* Here is my warning occuring in this line and the definition
line p_dir 'static DIR *p_dir = NULL' */
delete p_dir; // After changing this line with 'free(p_dir);' warnings gone.
p_dir = NULL;
}
}
The warning at the definition line (static DIR *p_dir = NULL;) is 'p_dir' has incomplete type and the warning at the delete line (delete p_dir;) is possible problem detected in invocation of delete operator: [-Wdelete-incomplete].
After changing the delete p_dir; with free(p_dir); the both warnings are gone.
I don't know it's exact reason but it sounds like DIR * type acting like void *. I'm just taking a wild guess.
Hope this helps.
Related
I'm very very new to C++.
In my current project I already included
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
and I just need to do a quick check in the very beginning of my main() to see if a required dll exists in the directory of my program.
So what would be the best way for me to do that?
So, assuming it's OK to simply check that the file with the right name EXISTS in the same directory:
#include <fstream>
...
void check_if_dll_exists()
{
std::ifstream dllfile(".\\myname.dll", std::ios::binary);
if (!dllfile)
{
... DLL doesn't exist...
}
}
If you want to know that it's ACTUALLY a real DLL (rather than someone opening a command prompt and doing type NUL: > myname.dll to create an empty file), you can use:
HMODULE dll = LoadLibrary(".\\myname.dll");
if (!dll)
{
... dll doesn't exist or isn't a real dll....
}
else
{
FreeLibrary(dll);
}
There are plenty ways you can achieve that, but using boost library is always a good way.
#include <boost/filesystem.hpp>
using boost::filesystem;
if (!exists("lib.dll")) {
std::cout << "dll does not exists." << std::endl;
}
I'm trying to take the approach of using swig with the main header file. It seems like swig will work doing this, but I've run into some problems. I asked a first question about it here on stackoverflow and while I haven't yet been successful, I've made enough progress to feel encouraged to continue...
So now, here's my interface file:
/* File : myAPI.i */
%module myAPI
%{
#include "stdafx.h"
#include <boost/algorithm/string.hpp>
... many other includes ...
#include "myAPI.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
using boost::format;
using namespace std;
using namespace boost::algorithm;
using namespace boost::serialization;
%}
/* Let's just grab the original header file here */
%include "myAPI.h"
As far as I can tell swig runs just fine. However, in the generated code it produces numerous definitions like this one:
SWIGINTERN int Swig_var_ModState_set(PyObject *_val) {
{
void *argp = 0;
int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_MY_API, 0 | 0);
if (!SWIG_IsOK(res)) {
SWIG_exception_fail(SWIG_ArgError(res), "in variable '""ModState""' of type '""MY_API""'");
}
if (!argp) {
SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in variable '""ModState""' of type '""MY_API""'");
} else {
MY_API * temp;
temp = reinterpret_cast< MY_API * >(argp);
ModState = *temp;
if (SWIG_IsNewObj(res)) delete temp;
}
}
return 0;
fail:
return 1;
}
Visual Studio 2010 complains with an error for each of these code blocks. The error is based on the temp var:
2>c:\svn\myapi\myapi_wrap.cxx(3109): error C2071: 'temp' : illegal storage class
I tried just to add a global declaration of this variable as an int to the swig generated _wrap.cxx file, but it didn't not work. (clearly a naive approach...).
Does anyone have some insight as to what I need to do to avoid this error?
Thanks in advance!
In my app I want to copy a file to the other hard disk so this is my code:
#include <windows.h>
using namespace std;
int main(int argc, char* argv[] )
{
string Input = "C:\\Emploi NAm.docx";
string CopiedFile = "Emploi NAm.docx";
string OutputFolder = "D:\\test";
CopyFile(Input.c_str(), string(OutputFolder+CopiedFile).c_str(), TRUE);
return 0;
}
so after executing this, it shows me in the D:HDD a file testEmploi NAm.docx
but I want him to create the test folder if it doesn't exist.
I want to do that without using the Boost library.
Use the WINAPI CreateDirectory() function to create a folder.
You can use this function without checking if the directory already exists as it will fail but GetLastError() will return ERROR_ALREADY_EXISTS:
if (CreateDirectory(OutputFolder.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// CopyFile(...)
}
else
{
// Failed to create directory.
}
The code for constructing the target file is incorrect:
string(OutputFolder+CopiedFile).c_str()
this would produce "D:\testEmploi Nam.docx": there is a missing path separator between the directory and the filename. Example fix:
string(OutputFolder+"\\"+CopiedFile).c_str()
#include <experimental/filesystem> // or #include <filesystem> for C++17 and up
namespace fs = std::experimental::filesystem;
if (!fs::is_directory("src") || !fs::exists("src")) { // Check if src folder exists
fs::create_directory("src"); // create src folder
}
Probably the easiest and most efficient way is to use boost and the boost::filesystem functions. This way you can build a directory simply and ensure that it is platform independent.
const char* path = _filePath.c_str();
boost::filesystem::path dir(path);
if(boost::filesystem::create_directory(dir))
{
std::cerr<< "Directory Created: "<<_filePath<<std::endl;
}
boost::filesystem::create_directory - documentation
Here is the simple way to create a folder.......
#include <windows.h>
#include <stdio.h>
void CreateFolder(const char * path)
{
if(!CreateDirectory(path ,NULL))
{
return;
}
}
CreateFolder("C:\\folder_name\\")
This above code works well for me.
_mkdir will also do the job.
_mkdir("D:\\test");
https://msdn.microsoft.com/en-us/library/2fkk4dzw.aspx
OpenCV Specific
Opencv supports filesystem, probably through its dependency Boost.
#include <opencv2/core/utils/filesystem.hpp>
cv::utils::fs::createDirectory(outputDir);
Since c++17, you can easily do this cross-platform with:
#include <filesystem>
int main() {
auto created_new_directory
= std::filesystem::create_directory("directory_name");
if (not created_new_directory) {
// Either creation failed or the directory was already present.
}
}
Note, that this version is very useful, if you need to know, whether the directory is actually newly created.
And I find the documentation on cppreference slightly difficult to understand on this point: If the directory is already present, this function returns false.
This means, you can more or less atomically create a new directory with this method.
Use CreateDirectory (char *DirName, SECURITY_ATTRIBUTES Attribs);
If the function succeeds it returns non-zero otherwise NULL.
You can use cstdlib
Although- http://www.cplusplus.com/articles/j3wTURfi/
#include <cstdlib>
const int dir= system("mkdir -p foo");
if (dir< 0)
{
return;
}
you can also check if the directory exists already by using
#include <dirent.h>
This works in GCC:
Taken from:
Creating a new directory in C
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct stat st = {0};
if (stat("/some/directory", &st) == -1) {
mkdir("/some/directory", 0700);
}
I somehow messed up the includes, but weren't able to actually find the error:
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef DEBUG
#define DLOG(x) printf(x)
#define PLOG(x,y) printf(x,y)
#else
#define DLOG(x)
#define PLOG(x,y)
#endif
harddrive::Results* harddrive::search_for(char* start,char* target,char** ignore,int size) {
PLOG("work directory: %s",start);
DIR* curr_dir = opendir(start);
Results* local = new Results;
if(!curr_dir) {
printf(" opendir() failure, probably no real directory: %s",start);
errno = 0;
return NULL;
}
struct dirent* elem;
while( (elem = readdir(curr_dir)) ) {
//form URI
char* uri = form_uri(start,curr_dir->d_name); //here is the actual error
struct stat st;
lstat(elem->d_name,&st);
if( S_ISDIR(st.st_mode) ) {
if( !do_ignore(uri,ignore,size) )
local = merge(local,search_for( form_uri(start,elem->d_name), target,ignore,size));
}
else if( S_ISREG(st.st_mode) ) { //this is line 41
Compiler output:
Directory.cpp: In function ‘harddrive::Results* harddrive::search_for(char*, char*, char**, int)’:
Directory.cpp:34:38: error: invalid use of incomplete type ‘struct DIR’
/usr/include/dirent.h:128:16: error: forward declaration of ‘struct DIR’
€:I am sorry for the inconvenience but i pasted an old error code, before I started switching around lines, but now it is correct.
curr_dir->d_name should be elem->d_name.
As the error says, you're incorrectly trying to dereference a pointer to the opaque type DIR.
DIR* is an opaque handle, you can't access its internals. You probably meant to access elem instead of curr_dir
i.e. change
form_uri(start,curr_dir->d_name);
to
form_uri(start,elem->d_name);
dirent.h says:
/* This is the data type of directory stream objects.
The actual structure is opaque to users. */
typedef struct __dirstream DIR;
I am trying to read a file which I read previously successfully.
I am reading it through a library, and I am sending it as-is to the library (i.e. "myfile.txt").
I know that the file is read from the working/current directory.
I suspect that the current/working directory has changed somehow.
How do i check what is the current/working directory?
Since you added the visual-c++ tag I'm going to suggest the standard windows function to do it. GetCurrentDirectory
Usage:
TCHAR pwd[MAX_PATH];
GetCurrentDirectory(MAX_PATH,pwd);
MessageBox(NULL,pwd,pwd,0);
Boost filesystem library provides a clean solution
current_path()
Use _getcwd to get the current working directory.
Here's the most platform-agnostic answer I got a while ago:
How return a std::string from C's "getcwd" function
It's pretty long-winded, but does exactly what it's supposed to do, with a nice C++ interface (ie it returns a string, not a how-long-are-you-exactly?-(const) char*).
To shut up MSVC warnings about deprecation of getcwd, you can do a
#if _WIN32
#define getcwd _getcwd
#endif // _WIN32
This code works for Linux and Windows:
#include <stdio.h> // defines FILENAME_MAX
#include <unistd.h> // for getcwd()
#include <iostream>
std::string GetCurrentWorkingDir();
int main()
{
std::string str = GetCurrentWorkingDir();
std::cout << str;
return 0;
}
std::string GetCurrentWorkingDir()
{
std::string cwd("\0",FILENAME_MAX+1);
return getcwd(&cwd[0],cwd.capacity());
}