gcc warning and 'basename'

K

KM

Questions about a compiler warning when using the 'basename'
library function...

This is my test program 'foo.c'.

#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = (char *) basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}

Compiling produces a warning.

$ gcc -Wall -c -o foo.o foo.c
foo.c: In function ‘main’:
foo.c:6: warning: implicit declaration of function ‘basename’

The #includes don't pull in a declaration of basename.

$ gcc -E foo.c | grep basename
char *bname = (char *) basename("/a/b/cdef");

The program links and runs, printing "bname is cdef."

What's going on with 'basename'?

Can I and should I modify the program to remove the compiler warning?

Thanks
 
I

Ian Collins

Questions about a compiler warning when using the 'basename'
library function...

This is my test program 'foo.c'.

#include<stdio.h>
#include<string.h>

int main (int argc, char **argv)
{
char *bname = (char *) basename("/a/b/cdef");

Why the cast?
printf("bname is %s.\n", bname);
return 0;
}

Compiling produces a warning.

$ gcc -Wall -c -o foo.o foo.c
foo.c: In function ‘main’:
foo.c:6: warning: implicit declaration of function ‘basename’

The #includes don't pull in a declaration of basename.

$ gcc -E foo.c | grep basename
char *bname = (char *) basename("/a/b/cdef");

The program links and runs, printing "bname is cdef."

What's going on with 'basename'?

Can I and should I modify the program to remove the compiler warning?

Yes, from the man page of basename, find and include the required header.
 
B

Barry Schwarz

Questions about a compiler warning when using the 'basename'
library function...

This is my test program 'foo.c'.

#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = (char *) basename("/a/b/cdef");

basename is not a standard C function but it appears to be part of
POSIX. You may have better luck asking in one of the unix groups.

As a general rule, you should declare a function with a prototype
prior to using the function. You need to find out what header file
contains the prototype for basename (man may tell you).

Your cast of the return value is apparently an attempt to silence the
warning about illegally converting an int to a pointer. That is
always the wrong approach for this problem. Once you include the
correct header, you will not need the cast.
 
S

Seebs

Questions about a compiler warning when using the 'basename'
library function...

This function is not a part of standard C, so you may get better
results in a group specific to your implementation -- or just
Read The Fine Manual.

Try "man 3 basename". (If you don't know why that works, or
what it does, "man man".)
#include <stdio.h>
#include <string.h>

These headers declare various standard functions.
int main (int argc, char **argv)
{
char *bname = (char *) basename("/a/b/cdef");

Here, you call a function which is not a standard function, and
has not been declared.
Compiling produces a warning.
Yes.

$ gcc -Wall -c -o foo.o foo.c
foo.c: In function ???main???:
foo.c:6: warning: implicit declaration of function ???basename???
The #includes don't pull in a declaration of basename.
Right.

The program links and runs, printing "bname is cdef."

That's nice. Presumably it's in the library on that system, and has a type
such that the implicit declaration was good enough. Note that you should
NEVER, EVER, rely on or use implicit declarations -- you would be well
served by adjusting your compiler options to cause gcc to refuse to compile
a program which uses them.
What's going on with 'basename'?

It's not declared.
Can I and should I modify the program to remove the compiler warning?

You should. I would guess that you can, too, but I wouldn't know off the
top of my head what non-standard header to use.

-s
 
N

Niklas Holsti

Ian said:
Questions about a compiler warning when using the 'basename'
library function...
[ snip ]
char *bname = (char *) basename("/a/b/cdef"); [ snip ]
Can I and should I modify the program to remove the compiler warning?

Yes, from the man page of basename, find and include the required header.

Moreover, at least on my system (Debian) the man page says that
basename() may modify the contents of its argument string, so passing a
string literal is a bit risky. The man page suggests to pass a
(throw-away) copy of the path name.
 
K

Keith Thompson

Ian Collins said:
Questions about a compiler warning when using the 'basename'
library function...

This is my test program 'foo.c'.

#include<stdio.h>
#include<string.h>

int main (int argc, char **argv)
{
char *bname = (char *) basename("/a/b/cdef");
[...]
What's going on with 'basename'?

Can I and should I modify the program to remove the compiler warning?

Yes, from the man page of basename, find and include the required header.

At least on my system (Ubuntu), the man page ("man 3 basename", not
"man basename") says there are two different functions of that name.
One of them is declared in <string.h>, but not by default.
 
K

KM

Thanks for your and the other replies. I had been consulting the GNU
'info' pages which show <string.h> as the header.

The 'man 3 basename' page says to use '#define _GNU_SOURCE'
immediately before the inclusion in order to use the GNU version of
basename. For me it made no difference except the line number in the
compiler warning.

However, on placing '#define _GNU_SOURCE' on the first source line the
warning disappears and the objectionable cast can go, i.e.

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}
 
K

Keith Thompson

KM said:
Thanks for your and the other replies. I had been consulting the GNU
'info' pages which show <string.h> as the header.

The 'man 3 basename' page says to use '#define _GNU_SOURCE'
immediately before the inclusion in order to use the GNU version of
basename. For me it made no difference except the line number in the
compiler warning.

However, on placing '#define _GNU_SOURCE' on the first source line the
warning disappears and the objectionable cast can go, i.e.

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}

Think about whether you want to use the GNU or POSIX version of
basename(). The POSIX version is substantially more portable;
the GNU version exists only on systems that use the GNU C library
(that's not even all systems that use gcc).

Portability isn't always important, but it's always worth thinking
about.
 
B

Barry Schwarz

Thanks for your and the other replies. I had been consulting the GNU
'info' pages which show <string.h> as the header.

The 'man 3 basename' page says to use '#define _GNU_SOURCE'
immediately before the inclusion in order to use the GNU version of
basename. For me it made no difference except the line number in the
compiler warning.

However, on placing '#define _GNU_SOURCE' on the first source line the
warning disappears and the objectionable cast can go, i.e.

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

Obviously, the define causes the inclusion of string.h to also process
some non-standard declarations. This is usually accomplished with the
#if family of preprocessor directives.
 
U

Uno

Think about whether you want to use the GNU or POSIX version of
basename(). The POSIX version is substantially more portable;
the GNU version exists only on systems that use the GNU C library
(that's not even all systems that use gcc).

Portability isn't always important, but it's always worth thinking
about.

I contend that we're still talking about C though, even though it has
devolved into something in which an implementation has been named.

http://i54.tinypic.com/1erk02.jpg

When you see a compiler/OS reaction like this, you'd probably think
you're on the wrong platform.
 
U

Uno

KM said:
Thanks for your and the other replies. I had been consulting the GNU
'info' pages which show <string.h> as the header.

The 'man 3 basename' page says to use '#define _GNU_SOURCE'
immediately before the inclusion in order to use the GNU version of
basename. For me it made no difference except the line number in the
compiler warning.

However, on placing '#define _GNU_SOURCE' on the first source line the
warning disappears and the objectionable cast can go, i.e.

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}

I was surprised with the non-failure here. Platform is ubuntu:

$ gcc -Wall -Wextra u1.c -o out.exe
u1.c:5: warning: unused parameter ‘argc’
u1.c:5: warning: unused parameter ‘argv’
$ ./out.exe
bname is cdef.
$ cat u1.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}


// gcc -Wall -Wextra u1.c -o out.exe
$ cc -Wall -Wextra u2.c -o out
u2.c: In function ‘main’:
u2.c:7: warning: implicit declaration of function ‘basename’
u2.c:7: warning: initialization makes pointer from integer without a cast
u2.c: At top level:
u2.c:5: warning: unused parameter ‘argc’
u2.c:5: warning: unused parameter ‘argv’
$ ./out
bname is cdef.
$ cat u2.c
//#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}


// gcc -Wall -Wextra u2.c -o out
$
 
U

Uno

Barry said:
Obviously, the define causes the inclusion of string.h to also process
some non-standard declarations. This is usually accomplished with the
#if family of preprocessor directives.

I don't think that's obvious. If you commented out the define and got
the same behavior, would it seem less obvious?
 
A

Alan Curry

I was surprised with the non-failure here. Platform is ubuntu: [...]


// gcc -Wall -Wextra u1.c -o out.exe
$ cc -Wall -Wextra u2.c -o out
u2.c: In function ‘main’:
u2.c:7: warning: implicit declaration of function ‘basename’
u2.c:7: warning: initialization makes pointer from integer without a cast

Those warnings look like failure to me. If you ignored them, the failure
is you. You need the compiler to smack you harder to get your attention?
Then use -Werror
u2.c: At top level:
u2.c:5: warning: unused parameter ‘argc’
u2.c:5: warning: unused parameter ‘argv’

Those can be fixed too, and should be, so you aren't tempted blow off
warnings in general like you apparently did.
 
M

Marcin Grzegorczyk

Uno said:
I was surprised with the non-failure here. Platform is ubuntu: [snip first, correct code]
$ cc -Wall -Wextra u2.c -o out
u2.c: In function ‘main’:
u2.c:7: warning: implicit declaration of function ‘basename’
u2.c:7: warning: initialization makes pointer from integer without a cast
u2.c: At top level:
u2.c:5: warning: unused parameter ‘argc’
u2.c:5: warning: unused parameter ‘argv’
$ ./out
bname is cdef.
$ cat u2.c
//#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}

If by "non-failure" you mean "the code appeared to work", then I don't
find that surprising. If it's a 32-bit Ubuntu, then pointers are the
same size as int. If it's a 64-bit Ubuntu, they're not, but luckily for
you, by default your code and data are located well below the 2G
threshold, so pointer values do not overflow an int.

If by "non-failure" you mean "GCC didn't reject that", well, I bet there
is some important-to-someone code out there that relies both on implicit
function declarations and implicit conversions between pointers and
integers. Note, by the way, that the latter causes a warning even with
neither -Wall nor -Wextra -- a sure sign that something really isn't right.
 
U

Uno

[x-posted to c.u.p.]


Barry said:
>
> Obviously, the define causes the inclusion of string.h to also process
> some non-standard declarations. This is usually accomplished with the
> #if family of preprocessor directives.
>

I wanted to take a closer look at what cpp is doing here. This is now
my source:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (void)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}


// gcc -Wall -Wextra -dM -E u1.c >text1.txt
// gcc -Wall -Wextra -dM -E u1.c >text2.txt

The idea here was that in the first run, I commented out the define, and
in the second run, I did not. So typical output for either one of those
looks like this:

....
#define __DEC32_MIN__ 1E-95DF
#define __S32_TYPE int
#define __DBL_MAX_EXP__ 1024
#define __DEC128_EPSILON__ 1E-33DL
#define _G_VTABLE_LABEL_PREFIX_ID __vt_
#define __FSFILCNT_T_TYPE __ULONGWORD_TYPE
#define _IO_LINKED 0x80
#define _G_HAVE_IO_GETLINE_INFO 1
#define _IO_HAVE_ST_BLKSIZE _G_HAVE_ST_BLKSIZE
#define __bounded
#define __USECONDS_T_TYPE __U32_TYPE
#define _IO_DELETE_DONT_CLOSE 0x40
....

Then I ran diff on these files, obtaining the following output:

19a20
> #define _XOPEN_SOURCE 600 70a72
> #define _ATFILE_SOURCE 1 98a101
> #define _LARGEFILE64_SOURCE 1 124a128
> #define _LARGEFILE_SOURCE 1 139a144,145
> #define __USE_ISOC95 1
> #define __USE_ISOC99 1 144a151,152
> #define __USE_LARGEFILE 1
> #define __USE_XOPEN 1 187a196
> #define __USE_GNU 1 193a203
> #define __USE_UNIX98 1 266a277
> #define _XOPEN_SOURCE_EXTENDED 1 268a280
> #define strndupa(s,n) (__extension__ ({ __const char *__old = (s);
size_t __len = strnlen (__old, (n)); char *__new = (char *)
__builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy
(__new, __old, __len); }))
273a286
> #define strdupa(s) (__extension__ ({ __const char *__old = (s);
size_t __len = strlen (__old) + 1; char *__new = (char *)
__builtin_alloca (__len); (char *) memcpy (__new, __old, __len); }))
285a299
> #define _VA_LIST_DEFINED 298a313
> #define _XLOCALE_H 1 334a350
> #define __USE_LARGEFILE64 1 360a377
> #define _ISOC99_SOURCE 1 403a421
> #define __USE_XOPEN_EXTENDED 1 416a435
> #define __USE_ATFILE 1 420a440
> #define _GNU_SOURCE

I have 2 questions. This output is as close to gobbledygook as it could
be for my stage of unix comprehension. Does it mean anything to more
experienced viewers? I would think that it would tell some story to a
person who sees certain tea leaves.

The other one really has my attention. The first line of source in the
only translation until began with what turned out to be the final line
from diff. Since the order of defines matters, I don't what to think of
this. What is cpp doing there?

Thanks for your comment, and cheers,
 
U

Uno

Alan said:
I was surprised with the non-failure here. Platform is ubuntu: [...]

// gcc -Wall -Wextra u1.c -o out.exe
$ cc -Wall -Wextra u2.c -o out
u2.c: In function ‘main’:
u2.c:7: warning: implicit declaration of function ‘basename’
u2.c:7: warning: initialization makes pointer from integer without a cast

Those warnings look like failure to me. If you ignored them, the failure
is you. You need the compiler to smack you harder to get your attention?
Then use -Werror

Jesalmighty, miss the morning cup of joe? I didn't ignore these; I
created them intentionally.
Those can be fixed too, and should be, so you aren't tempted blow off
warnings in general like you apparently did.

It's not my source. Please take a look at what I posted in c.u.p.

Cheers,
 
U

Uno

Marcin said:
Uno said:
I was surprised with the non-failure here. Platform is ubuntu: [snip first, correct code]
$ cc -Wall -Wextra u2.c -o out
u2.c: In function ‘main’:
u2.c:7: warning: implicit declaration of function ‘basename’
u2.c:7: warning: initialization makes pointer from integer without a cast
u2.c: At top level:
u2.c:5: warning: unused parameter ‘argc’
u2.c:5: warning: unused parameter ‘argv’
$ ./out
bname is cdef.
$ cat u2.c
//#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}

If by "non-failure" you mean "the code appeared to work", then I don't
find that surprising. If it's a 32-bit Ubuntu, then pointers are the
same size as int. If it's a 64-bit Ubuntu, they're not, but luckily for
you, by default your code and data are located well below the 2G
threshold, so pointer values do not overflow an int.

If by "non-failure" you mean "GCC didn't reject that", well, I bet there
is some important-to-someone code out there that relies both on implicit
function declarations and implicit conversions between pointers and
integers. Note, by the way, that the latter causes a warning even with
neither -Wall nor -Wextra -- a sure sign that something really isn't right.

How does the linker find basename when we don't give it any help?
 
N

Nick Keighley

Marcin said:
Uno said:
I was surprised with the non-failure here. Platform is ubuntu: [snip first, correct code]
$ cc -Wall -Wextra u2.c -o out
u2.c: In function ‘main’:
u2.c:7: warning: implicit declaration of function ‘basename’
u2.c:7: warning: initialization makes pointer from integer without a cast
u2.c: At top level:
u2.c:5: warning: unused parameter ‘argc’
u2.c:5: warning: unused parameter ‘argv’
$ ./out
bname is cdef.
$ cat u2.c
//#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
int main (int argc, char **argv)
{
char *bname = basename("/a/b/cdef");
printf("bname is %s.\n", bname);
return 0;
}
If by "non-failure" you mean "the code appeared to work", then I don't
find that surprising.  If it's a 32-bit Ubuntu, then pointers are the
same size as int.  If it's a 64-bit Ubuntu, they're not, but luckily for
you, by default your code and data are located well below the 2G
threshold, so pointer values do not overflow an int.
If by "non-failure" you mean "GCC didn't reject that", well, I bet there
is some important-to-someone code out there that relies both on implicit
function declarations and implicit conversions between pointers and
integers.  Note, by the way, that the latter causes a warning even with
neither -Wall nor -Wextra -- a sure sign that something really isn't right.

How does the linker find basename when we don't give it any help?

it must be in one of the libraries you linked with. Since the
declaration is in string.h maybe its in the standard library include.
RTFM...
 
N

Noob

KM said:
Questions about a compiler warning when using the 'basename'
library function...

This is my test program 'foo.c'.

#include<stdio.h>
#include<string.h>

int main (int argc, char **argv)
{
char *bname = (char *) basename("/a/b/cdef");

On a somewhat related note, you might want to look into strrchr.
 
A

Alan Curry

[x-posted to c.u.p.]

And changed the subject to "companion processors"? Baffling.
The idea here was that in the first run, I commented out the define, and
in the second run, I did not. So typical output for either one of those
looks like this:

...
#define __DEC32_MIN__ 1E-95DF
#define __S32_TYPE int [...]

Then I ran diff on these files, obtaining the following output:

19a20
#define _XOPEN_SOURCE 600
[...]
420a440
#define _GNU_SOURCE

I have 2 questions. This output is as close to gobbledygook as it could
be for my stage of unix comprehension. Does it mean anything to more
experienced viewers? I would think that it would tell some story to a
person who sees certain tea leaves.

The chunk headers in the default diff output format (19a20, 420a440, etc.)
are similar to ed(1) commands that would transform the first file into the
second file. 19a20 means "a"ppend a line after line 19 of the first file,
which becomes line 20 of the second file. These commands would have been
easily recognizable at one time, but usage of ed has declined significantly
since then.

That's why almost everybody prefers the GNU unified diff format (diff -u)
these days. It's more reader-friendly. Before diff -u came around, the
popular format was diff -c.
The other one really has my attention. The first line of source in the
only translation until began with what turned out to be the final line
from diff. Since the order of defines matters, I don't what to think of
this. What is cpp doing there?

The order of the -dM output doesn't correspond to anything in the source
file. It waits until the end of the file, then dumps all the macros in some
semi-random order, probably based on an internal hash table. Since it dumps
at the end, it also misses things like this:

#define foo bar
int foo;
#undef foo
#define foo baz
int foo;

With -dD, you get the full preprocessed source with #defines shown in order.
Even then, the #define on the first line of your source file would still not
be the first thing in the listing, since there are a lot of macros built in
to the compiler. The builtin macros come first, then the -D command line
options, then the source file.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

QoI issue: silencing a warning 31
error and warning 12
Warning 12
Compile error 12
strcpy(s, "ABC"); gives a warning why... 4
Compiler warning about comparison always false 11
Compiling fics-1.7.4 3
Warnings with gcc 34

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top