Gettling a list of files within a directory - c

I am working on a C project where I need to get the list of files that are within a directory. I am using dirent.h but am having some problems getting it to work, I am building the program under Linux.
When I try and build the program I get the following error
myClass:error: âDIRâ undeclared (first use in this function)
myClass:408: error: (Each undeclared identifier is reported only once
myClass:408: error: for each function it appears in.)
myClass:408: error: âdirâ undeclared (first use in this function)
myClass:410: warning: implicit declaration of function âopendirâ
myClass:413: warning: implicit declaration of function âreaddirâ
myClass:413: warning: assignment makes pointer from integer without a cast
myClass:415: error: dereferencing pointer to incomplete type
myClass:417: warning: implicit declaration of function âclosedirâ
Below is the code that I am using
int logMaintenance(void *arg)
{
DIR *dir;
struct dirent *ent;
dir = opendir(directory);
if (dir != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
printf("%s\n", ent->d_name);
}
closedir(dir);
}
else
{
printf("Failed to read directory %i", EXIT_FAILURE);
}
return 0;
}
I don't understand what these errors mean especially when it says that DIR is undeclared when I have included the dirent.h header file for Liunux.
Thanks for your help.

You should make sure that:
You #include <dirent.h>, rather than "dirent.h", so that the system search path for headers is used to locate that file
You don't have a dirent.h file lying around somewhere in your project that could be picked up instead.
When trying to debug this type of strange problem, ask GCC for the pre-processed output with gcc -E. You can see what files (including the paths) it's including. That can help a lot.
And if you're using Microsoft Visual Studio, head over to this question:
Microsoft Visual Studio: opendir() and readdir(), how?

I'm not sure, but it seems like I was always told that you always need a main function...
However I have only a mere 8 months (2 semesters) of C++ under my belt. I just practice it to be safe, however, I would also use:
int main(int argc, char **argv) or
int main(int argc, char *argv[]) rather than
int logMaintenance(void *arg)
(while using dirent.h).

Related

Mingw -- Conflicting types for function due to previous declaration

To start off, I don't get this issue when I compile/"make" the code on a Linux machine which I connect to remotely. I'm experiencing it only on my Windows laptop with Mingw installed -- which I believe is causing the issue.
$ make
gcc -c parser.c
parser.c:34:7: error: conflicting types for 'gets'
34 | char* gets(char *buf, int max)
| ^~~~
In file included from parser.h:4,
from parser.c:1:
c:\mingw\include\stdio.h:709:41: note: previous declaration of 'gets' was here
709 | _CRTIMP __cdecl __MINGW_NOTHROW char * gets (char *);
| ^~~~
Makefile:13: recipe for target 'parser.o' failed
make: *** [parser.o] Error 1
Here's the gets() code as requested:
char* gets(char *buf, int max)
{
int i, cc;
char c;
for(i=0; i+1 < max; ){
cc = read(0, &c, 1);
if(cc < 1) break;
//c = getchar();
buf[i++] = c;
if(c == '\n' || c == '\r')
break;
}
buf[i] = '\0';
return buf;
}
Is there a way to fix this without changing the gets function name? Thank you sm
Your code works on Linux's gcc because the gets function was removed, as it should, since it was deprecated in the C99 standard and removed with C11.
For some reason the Windows MingW distribution still maintains gets and because of that you have a redefinition problem.
So unfortunately you can't use that function name, unless you remove it by hand from stdio.h, as C doesn't allow for function overloading.
Running sample on Linux gcc
Running sample on Windows gcc
As the error says the gets() function is already defined in stdio.h.
One trick you can do is put something like this:
#define gets MY_gets
before your definition of the gets() function.
That way you are actually defining a MY_gets() function which causes no conflict. And when you call gets() later on in your code you are actually calling MY_gets().
If you define gets() in a header file you should include stdio.h first and then put #define gets MY_gets before the declaration of gets() in the header file.
Though I don't see why you want to refine this function if it already exists.
It makes more sense to only define it if needed and surround the function with something like #ifndef HAVE_GETS and endif where HAVE_GETS should be defined based on tests done in the configure/build system.

How to handle error: expected expression before ‘do’ when there is no "do"?

I get the following compiler error, even though there is no "do" expression in my code.
gcc -Wall -g -c main.c -lasound
In file included from /usr/include/alsa/asoundlib.h:49:0,
from main.c:2:
main.c: In function ‘main’:
main.c:8:5: error: expected expression before ‘do’
if(snd_pcm_hw_params_alloca(&params) < 0) {
^
main.c:6:30: warning: unused variable ‘params’ [-Wunused-variable]
snd_pcm_hw_params_t *params;
^~~~~~
Makefile:15: recipe for target 'main.o' failed
make: *** [main.o] Error 1
From the following minimal reproducible example:
#include <stdio.h>
#include <alsa/asoundlib.h>
int main(int argc, char **argv)
{
snd_pcm_hw_params_t *params;
if(snd_pcm_hw_params_alloca(&params) < 0) {
return 0;
}
exit(0);
}
I'm aware this is not a valid ALSA program. I'm also aware that it appears snd_pcm_hw_params_alloca() doesn't even return anything worthwhile to check for errors against? That's not relevant though, this should valid C code regardless, even if it abuses the API.
Where is the "do" expression? If I go to /usr/include/alsa/asoundlib.h and poke around there, I don't see anything obvious that would indicate a problem.
If I remove the conditional if test, and get:
#include <stdio.h>
#include <alsa/asoundlib.h>
int main(int argc, char **argv)
{
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
exit(0);
}
This will compile with no errors.
What is this?
If I look in pcm.h, I see:
#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params)
int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr);
void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj);
void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src);
However, this doesn't tell me anything. Why does the compiler produce this error?
I'm also aware that it appears snd_pcm_hw_params_alloca() doesn't even return anything worthwhile to check for errors against? That's not relevant though, this should valid C code regardless, even if it abuses the API.
No, if snd_pcm_hw_params_alloca() does not have a value you cannot compare it against 0. For example, the following is also invalid:
void func(void) { }
void other(void) {
if (func() < 0) { // Error
}
}
In reality, snd_pcm_hw_params_alloca() is a macro, and it’s a wrapper for another macro, __snd_alloca. The do is there to make it behave more like a statement. You can only call it as a statement on its own line, or anywhere else where a do loop is legal.
snd_pcm_hw_params_alloca(&params);
You cannot check for errors because alloca() does not check for errors. If alloca() fails, it will just stomp on your stack, and bad things will happen. You can’t do anything about it, except not use alloca() (this is why you might hear advice to avoid alloca).
For an explanation of why the do loop is used, see: C multi-line macro: do/while(0) vs scope block
For more information about how alloca() works, see: Why is the use of alloca() not considered good practice?

Multiple definition of `main' while bison output file compiling

So I'm writing a bison (without lex) parser and now I want to read the input code from file and to write the output to another file.
Searching the stackoverflow for some time I found that this way should be good.
bison.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern FILE *yyin;
int yylex() { return getc(stdin); }
void yyerror(char *s) {
fprintf (stderr, "%s\n", s);
}
int counter = 1;
char filename2[10] = "dest.ll";
FILE *f2;
%}
%name parse
%%
//grammars
%%
int main(int argc, char *argv[]) {
yyin = fopen(argv[1], "r");
if (argc > 2)
f2 = fopen(argv[2], "w");
else
f2 = fopen(filename2, "w");
yyparse();
return 0;
}
Then i compile it this way:
bison bison.y
cc -ly bison.tab.c
And here the result of cc-compilation:
/tmp/ccNqiuhW.o: In function `main':
bison.tab.c:(.text+0x960): multiple definition of `main'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/liby.a(main.o):(.text.startup+0x0): first defined here
/tmp/ccNqiuhW.o: In function `main':
bison.tab.c:(.text+0x98c): undefined reference to `yyin'
collect2: error: ld returned 1 exit status
The output bison.tab.c file have only 1 main. Ofc int/void main doesn't matter. Can you teach me how to do it correctly?
P.S. By the way, I don't want to spam different posts, and have a little question here. How can I store the string (char *) in $$ in bison? For example, I want to generate a code string after I met the int grammar. I have this error and can't find the answer:
bison.y:94:8: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
INTNUM: NUMBER | DIGIT INTNUM {$$ = "string"};
bison.y: In function ‘yyparse’:
bison.y:28:15: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
PROGRAM: EXPRS { fprintf(f2, "%s: string here %d.\n", $$, counter++) };
will be extremely good if I find the help.
You are linking library liby (linker option -ly). The Bison manual has this to say about it:
The Yacc library contains default implementations of the yyerror and
main functions.
So that's why you have multiple definitions of main. You provide one, and there's one in liby.
Moreover, the docs go on to say that
These default implementations are normally not useful, but POSIX requires them.
(Emphasis added)
You do not need to link liby in order to build a program that includes a bison-generated parser, and normally you should not do so. Instead, provide your own main() and your own yyerror(), both of which you've already done.
Additionally, you are expected to provide a definition of yyin, not just a declaration, whether you link liby or not. To do so, remove the extern keyword from the declaration of yyin in your grammar file.
Your grammar is not complete (there are no rules at all) and the %name directive is not documented and is not recognized by my Bison, but if I add a dummy rule and comment out the %name, in conjunction with the other changes discussed, then bison generates a C source file for me that can be successfully compiled to an executable (without liby).

Listing files in Directory in Ubuntu

I am trying to list files in the parent directory of the current directory, but when I try to execute this program from terminal I get Segmentation Error.. What am I doing wrong? Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
struct dirent *dirpent;
DIR *dirp;
if(argc!=2)
{
printf("Cant continue with the program\n");
return 0;
}
dirp= opendir(argv[1]);
if(dirp)
{
while(dirpent=readdir(dirp) !=NULL)
printf("%s\n",dirpent->d_name);
closedir(dirp);
}
return 0;
}
dirpent=readdir(dirp) !=NULL
should be
(dirpent = readdir(dirp)) != NULL
Your current expression is parsed as dirpent = (readdir(dirp) != NULL), which will set dirpent to either 0 or 1.
If you indent your program with indent rd.c then compile your program with gcc -Wall -g rd.c -o rd you get
rd.c: In function 'main':
rd.c:21:22: warning: assignment makes pointer from integer without a cast [enabled by default]
rd.c:21:7: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
So you forgot parenthesis, your while should be
while((dirpent=readdir(dirp)) !=NULL)
Please compile your program with all warnings (and improve it till they are all gone) before asking questions. Use the gdb debugger (and its bt command) to find out why a program crash with SIGSEGV.
Don't forget to carefully read documentation like readdir(3) man page and Advanced Linux Programming book.

Problem with compiling C code

I'm using Dev-C++ 4.9.9.2 with MinGW to compile this code:
/* get the information about the group. */
struct group* group_info = getgrnam("PLACEHOLDER");
/* make sure this group actually exists. */
if (!group_info) {
printf("group 'PLACEHOLDER' does not exist.\n");
}
else
{
char** p_member;
printf("Here are the members of group 'PLACEHOLDER':\n");
for (p_member = group_info->gr_mem; *p_member; p_member++)
printf(" %s\n", *p_member);
}
}
I included the following header files:
grp.h
sys/types.h
(got them from glibc 2.13 (maybe this is wrong, but a friend told me this is the right way))
when I try to compile the code, i get a bunch of errors in the headers from glibc, like:
12 C:\glibc-2.9\include\sys\cdefs.h expected constructor, destructor, or type conversion before '(' token
12 C:\glibc-2.9\include\sys\cdefs.h expected `,' or `;' before '(' token
4 C:\glibc-2.9\include\grp.h expected constructor, destructor, or type conversion before '(' token
Edit:
This is the whole Code
#include <grp.h> /* defines 'struct group', and getgrnam(). */
#include <sys/types.h> /* defines 'gid_t', etc. */
BOOL getListOfGroupMembers() {
/* get the information about the "strange" group. */
struct group* group_info = getgrnam("PLACEHOLDER");
/* make sure this group actually exists. */
if (!group_info) {
printf("group 'PLACEHOLDER' does not exist.\n");
}
else
{
char** p_member;
printf("Here are the members of group 'PLACEHOLDER':\n");
for (p_member = group_info->gr_mem; *p_member; p_member++)
{
printf(" %s\n", *p_member);
}
}
return 0;
}
The bool return doesn't make sense at the moment, I want to change that when compiling works.
You can't just bring over a couple of header files from glibc over to mingw on windows. These header files are not self contained, they need a lot of other header files, and probably might even need to be installed on a system (not just refered to in the glibc source folders..)
Besides that, glibc isn't made for windows - these header files are crafted specifically for glibc, and win32 doesn't have the getgrnam() function anyway. (You'd need cygwin, which has its own header files)
There is a missing brace in the lowest for-loop, but maybe it is just a posting error?
I doubt this is the source of the problem, but it looks like your for has a closing bracket }, but lacks and opening one.

Resources