Why an argument can be outside of ( ) in a function definition? - gcc

I have a piece of code in my .y file as follows
void yyerror(s) char *s; {
fputs(s, stderr);
putc('\n', stderr);
}
The function prototype declaration is in another file as follows
void yyerror (char const *s);
I tried to compile the code on both Linux and mac. On Linux, the compiler generates the following error message
error: argument ‘s’ doesn’t match prototype
void yyerror(s) char *s; {
^
On mac, the compiler generates the following warning message
warning: promoted type 'char *' of K&R function parameter is not compatible with the parameter type 'const char *' declared in a previous prototype [-Wknr-promoted-parameter]
void yyerror(s) char *s; {
^
My questions are:
Why clang only generates warning while cc generates an error.
Both compilers complain about 's' in "char *s". Why they ignore the 's' in () but consider the second 's' as the argument?

Related

Weird behavior of basename() on Mac OS

I have a simple program to test basename() method:
#include <stdio.h>
#include <string.h>
//#include <libgen.h>
int main (int argc , char **argv)
{
char *a = strdup("test();");
printf("%s", basename(a));
return 0;
}
clang complains but it compiles anyway.
test.c:7:18: warning: implicit declaration of function 'basename' is invalid in C99 [-Wimplicit-function-declaration]
printf("%p", basename(a));
^
test.c:7:18: warning: format specifies type 'void *' but the argument has type 'int' [-Wformat]
printf("%p", basename(a));
And it results in segfault. But if I added libgen.h header, it works normally.
I've checked the binary with otool, it linked against the same dylib, nothing else. Why does the first one crash?
I've checked the answer here already, it uses a static buffer but I use the result from strdup(), so it's a different question.

The result of using strtol() under stdlib.h and stdio.h is different

When trying to parse a number too big to fit a long, strtol() returns 0 instead of LONG_MAX (stdio.h). If I read the POSIX spec correctly, it should be LONG_MAX. There is a different between stdio.h and stdlib.h
#include "stdio.h"
int main(void){
printf("%ld\n", strtol("99999999999999999999999"));
return 0;
} # 0
#include "stdio.h"
//#include "stdlib.h"
int main(void){
char *end[500];
printf("%ld\n", strtol("99999999999999999999999", end, 10));
return 0;
} # 9223372036854775807
strtol is declared in header <stdlib.h> as
long strtol( const char *restrict str, char **restrict str_end, int base );
// ^^^^^^^^ ^^^^^^^^ since C99
In the first posted snippet, <stdlib.h> is not included and the function is called with one single argument, so that, if compiled with -Wall -Wextra -std=gnu11, gcc produces the following explanatory warnings before outputting 0:
prog.c: In function 'main':
prog.c:5:21: warning: implicit declaration of function 'strtol' [-Wimplicit-function-declaration]
printf("%ld\n", strtol("99999999999999999999999"));
^~~~~~
prog.c:5:15: warning: format '%ld' expects argument of type 'long int', but argument 2 has type 'int' [-Wformat=]
printf("%ld\n", strtol("99999999999999999999999"));
~~^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%d
Which means that the library function is not called at all and an implicitly declared function with the same name is called, an int with value 0 is returned and printed (with the wrong format specifier, which is itself undefined behavior).
Note that the same code fails to compile with clang, which reports the following:
prog.c:4:21: warning: implicitly declaring library function 'strtol' with type 'long (const char *, char **, int)' [-Wimplicit-function-declaration]
printf("%ld\n", strtol("99999999999999999999999"));
^
prog.c:4:21: note: include the header &ltstdlib.h&gt or explicitly provide a declaration for 'strtol'
prog.c:4:53: error: too few arguments to function call, expected 3, have 1
printf("%ld\n", strtol("99999999999999999999999"));
~~~~~~ ^
1 warning and 1 error generated.
In the second snippet, strtol is called with the right number of arguments, but, as posted (with the #include commented out), has the same missing header problem. To produce the expected output, LONG_MAX, header stdlib.h has to be included.

clang accepts "static_cast<const int&>" using "explicit operator int() const", gcc/VS reject

Given this c++11 code: (everything remains the same compiling as c++14 or c++17)
class typeSafe {
public:
typeSafe(int tValue)
: value(tValue) {
}
explicit operator int() const {
return value;
}
private:
int value;
};
int main() {
typeSafe x{5};
typeSafe y{5};
if(static_cast<const int&>(x) == static_cast<const int&>(y)) {
}
}
The controversy is because the static_cast attempts converting to a const int&, but the explicit operator gives an int, not an int&.
clang 5.0.0 silently compiles it, with every warning turned on.
gcc rejects it, with:
typeSafe.cpp: In function ‘int main()’:
typeSafe.cpp:17:32: error: invalid static_cast from type ‘typeSafe’ to type ‘const int&’
if(static_cast<const int&>(x) == static_cast<const int&>(y)) {
^
typeSafe.cpp:17:62: error: invalid static_cast from type ‘typeSafe’ to type ‘const int&’
if(static_cast<const int&>(x) == static_cast<const int&>(y)) {
^
Visual Studio 2017 15.5 Preview 2 rejects it, with:
typeSafe.cpp(17): error C2440: 'static_cast': cannot convert from 'typeSafe' to 'const int &'
typeSafe.cpp(17): note: Reason: cannot convert from 'typeSafe' to 'const int'
typeSafe.cpp(17): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Note if the static_cast attempts converting to an int&, then all 3 compilers reject it, with clang saying:
typeSafe.cpp:17:7: error: non-const lvalue reference to type 'int' cannot
bind to a value of unrelated type 'typeSafe'
if(static_cast<int&>(x) == static_cast<int&>(y)) {
^ ~
typeSafe.cpp:17:31: error: non-const lvalue reference to type 'int' cannot
bind to a value of unrelated type 'typeSafe'
if(static_cast<int&>(x) == static_cast<int&>(y)) {
^ ~
So, who's right and who's wrong?

GCC gives confusing warning message when using pointer to struct <typedef>

On compiling the following C program, GCC emits a warning message which is somewhat confusing.
Program Source
#include <stdio.h>
typedef struct {
int x;
} dummy_t;
void myfunc (dummy_t *pointer)
{
printf("x = %d\n", pointer->x);
}
int main ()
{
dummy_t d = { 10 };
/* INCORRECT. */
myfunc((struct dummy_t *)&d);
/* Correct. */
// myfunc((dummy_t *)&d);
return 0;
}
Compilation
bash$ gcc c.c
c.c: In function ‘main’:
c.c:17:20: warning: passing argument 1 of ‘myfunc’ from incompatible pointer type
myfunc((struct dummy_t *)&d);
^
c.c:7:6: note: expected ‘struct dummy_t *’ but argument is of type ‘struct dummy_t *’
void myfunc (dummy_t *pointer)
Notice how both the expected type and the argument type are reported to have the same value struct dummy_t *. This is confusing.
Shouldn't the expected type be dummy_t *?
The above program is a simplified version of the actual code where I faced this problem.
GCC Version
bash$ gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
You're right that the error message is confusing. A newer version gives a much better error message:
note: expected 'dummy_t * {aka struct <anonymous> *}' but argument is
of type 'struct dummy_t *'
As you can see, dummy_t and struct dummy_t are different types. With this declaration:
typedef struct {
int x;
} dummy_t;
You are typedef'ing an anonymous struct. However, later when you do struct dummy_t, you are forward declaring a new struct named dummy_t. Clearly, these are two different types, hence the error.

GCC: Customizing printf for string output

GCC allows customization of printf specifiers. However, I don't see how I can "teach" it to accept my string class for %s specifier. My string class is a simple wrapper over char pointer and has exactly one member variable (char * data) and no virtual functions. So, it's kind of ok to pass it as-is to printf-like functions in place of regular char *. The problem is that on gcc static analyzer prevents me from doing so and I have to explicitly cast it to const char * to avoid warnings or errors.
My cstring looks something like this:
class cstring
{
cstring() : data(NULL){}
cstring(const char * str) : data(strdup(str)){}
cstring(const cstring & str) : data(strdup(str.data)){}
~cstring()
{
free(data);
}
...
const char * c_str() const
{
return data;
}
private:
char * data;
};
Example code that uses cstring:
cstring str("my string");
printf("str: '%s'", str);
On GCC I get this error:
error: cannot pass objects of non-trivially-copyable type 'class cstring' through '...'
error: format '%s' expects argument of type 'char*', but argument 1 has type 'cstring' [-Werror=format]
cc1plus.exe: all warnings being treated as errors
The C++ standard doesn't require compilers to support this sort of code, and not all versions of gcc support it. (https://gcc.gnu.org/onlinedocs/gcc/Conditionally-supported-behavior.html suggests that gcc-6.0 does, at least - an open question whether it will work with classes such as the one here.)
The relevant section in the C++11 standard is 5.2.2 section 7:
When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg ...
Passing a potentially-evaluated argument of class type (Clause 9)
having a non-trivial copy constructor, a non-trivial move constructor,
or a non-trivial destructor, with no corresponding parameter, is
conditionally-supported with implementation-defined semantics.
(But look on the bright side: if you get into the habit of using c_str, then at least you won't get tripped up when/if you use std::string.)

Resources