What does putting void; on a line do in C? The compiler is warning about it but i dont understand. What is the point in being able to put void on a line like this?
#include <stdio.h>
int main() {
void;
printf("word dude");
return 1;
}
eh
$ gcc -pedantic -ansi -Wall -Wextra eh.c -o eh
eh.c: In function 'main':
eh.c:4:2: warning: useless type name in empty declaration
$ ./eh
word dude
People seem to be getting confused what I'm asking: What does this line mean, does it do anything? why is it valid?
void;
Removed void cast as it's causing unnecessary discussion.
This question got me interested because my first thought was K&R. I went back to my old K&R book (Appendix A p.192) on found blurb about declarations (transcripted):
8. Declarations
Declarations are used to specify the interpretation which C gives to each identifier; they do not necessarily reserve storage associated with the identifier. Declarations have
the form
declaration:
decl-specifier declarator-listopt;
The declarators in the declarator-list contain the identifiers being declared. The decl-specifiers consist of a sequence of type and storage class specifiers.
decl-specifiers:
type-specifier decl-specifiersopt
sc-specifier decl-specifiersopt
This leads me to believe that delarator lists are optional (meaning it can be empty).
To add to this confusion on following page, it lists the set of legal type-specifier values and void is not one of them.
In my narrow interpretation that this may be still legal (but obsolete) C.
void; // 1
(void)printf("word dude"); // 2
The first statement is an invalid statement: this is not C.
In the second statement the (void) cast makes your intent clear to discard the return value. Another common use is to make silent some static analysis tools like Lint.
void;
There's no point in doing that, it doesn't do anything.
Did you get this out of a book? Must be a mistake.
Somewhat unrelated, a return value if 0 is usually used to indicate the program terminated normally, any other value indicates a problem (by convention)
Update:
Looks like you added another line:
(void)printf("word dude");
this - unlike the previous void; - tells the compiler explictly to ignore the return value of the printf() function (the number of characters printed) and prevent warning messages a picky/pedantic setting on the compiler or other tools, like lint, to stop from complaining.
You don't see this for frequently used functions generally, though you may for others.
It prints the same error if you change void with int or any other type.
void is a type and it expects something after that type. It has no sense at all as writing only int without a variable (or function) name after it.
void is used as a data type in C, and come to think of it, I've never heard of an assembly language equivalent of NOP in C, so having void by itself on a line is probably an error.
It looks like the old style of declaring arguments to a function. That's equivalent to int main(void). Some compilers still accept it, some don't. For example, this code compiles in two compilers I tried:
void main(i, j) {
int;
long;
i = 12;
j = 123456;
printf("%d %d\n", i, j);
}
The answer to Untyped arguments in a C function declaration has a more precise definition for this case.
In any case, this is not recommended, so can we just stick with the "normal" way of declaring functions, please? :)
Related
I'm trying to understand the use of the "static" keyword as an array index in a function declaration in C.
After reading this article, I tried to declare such a function, and purposefully passing it an array that is too short:
#include <stdio.h>
#include <stdlib.h>
void print_string10(char string10[static 10]) {
// Should trigger a warning if the argument is NULL or an array of less than 10 elements
printf("%s\n",string10);
}
int main(void) {
char short_string[] = "test";
print_string10(short_string); // should trigger a warning as the string is 5 long
return EXIT_SUCCESS;
}
Compiling with clang as in the article triggers the warning, but gcc -Wall -Werror does not, it compiles and run fine.
I couldn't find an explanation, is that a normal behaviour for GCC to omit this warning?
Why it does not need to trigger a warning is because of the section of the standard where it occurs - 6.7.6.3p7:
Semantics
[...]
A declaration of a parameter as ''array of type'' shall be adjusted to ''qualified pointer to type'', where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
It appears in the semantics section. A conforming implementation is only required to diagnose those that appear in the constraints. Even when it does not diagnose the violation here, it can use the knowledge of the static keyword to infer that the argument is not null, and that loop unrolling and other optimizations could expect an array that would have at least that many elements.
Do also note, that the example 5 there says that
void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);
are all compatible, i.e. you can mix and match them in function pointer assignments without casts even though one has the static dimension!
It seems that clang (perhaps rightly so) loses its ability to diagnose anything if the call is realized through a function pointer:
void (*f)(double a[restrict static 3]);
int main(void) {
double a[1] = {0};
f(a);
}
(no diagnostics in Clang 7.0 - remove the * and you will get them).
It looks like this is a bug in GCC. It seems there were some disagreements regarding whether or not this should be reported at compile time. Nonetheless, it was accepted as a bug but there doesn't seem to be a priority on fixing it.
This is detailed in bug report 50584. Comment 9 in particular states:
(In reply to Malcolm Inglis from comment #4)
Could someone change the status of this bug?
Notwithstanding whether the feature is pretty or ugly, GCC does accept
this code and warnings for undefined behavior, when possible, are
desired. Thus, confirmed.
This does not mean anyone is going to work on fixing this. Please, if
you are using this feature and would like to see this warning in GCC,
please consider contributing it:
https://gcc.gnu.org/wiki/GettingStarted#Basics:_Contributing_to_GCC_in_10_easy_steps
If you start working on this, it would be good to say so here.
I'm trying to understand the use of the "static" keyword as an array index in a function declaration in C.
After reading this article, I tried to declare such a function, and purposefully passing it an array that is too short:
#include <stdio.h>
#include <stdlib.h>
void print_string10(char string10[static 10]) {
// Should trigger a warning if the argument is NULL or an array of less than 10 elements
printf("%s\n",string10);
}
int main(void) {
char short_string[] = "test";
print_string10(short_string); // should trigger a warning as the string is 5 long
return EXIT_SUCCESS;
}
Compiling with clang as in the article triggers the warning, but gcc -Wall -Werror does not, it compiles and run fine.
I couldn't find an explanation, is that a normal behaviour for GCC to omit this warning?
Why it does not need to trigger a warning is because of the section of the standard where it occurs - 6.7.6.3p7:
Semantics
[...]
A declaration of a parameter as ''array of type'' shall be adjusted to ''qualified pointer to type'', where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
It appears in the semantics section. A conforming implementation is only required to diagnose those that appear in the constraints. Even when it does not diagnose the violation here, it can use the knowledge of the static keyword to infer that the argument is not null, and that loop unrolling and other optimizations could expect an array that would have at least that many elements.
Do also note, that the example 5 there says that
void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);
are all compatible, i.e. you can mix and match them in function pointer assignments without casts even though one has the static dimension!
It seems that clang (perhaps rightly so) loses its ability to diagnose anything if the call is realized through a function pointer:
void (*f)(double a[restrict static 3]);
int main(void) {
double a[1] = {0};
f(a);
}
(no diagnostics in Clang 7.0 - remove the * and you will get them).
It looks like this is a bug in GCC. It seems there were some disagreements regarding whether or not this should be reported at compile time. Nonetheless, it was accepted as a bug but there doesn't seem to be a priority on fixing it.
This is detailed in bug report 50584. Comment 9 in particular states:
(In reply to Malcolm Inglis from comment #4)
Could someone change the status of this bug?
Notwithstanding whether the feature is pretty or ugly, GCC does accept
this code and warnings for undefined behavior, when possible, are
desired. Thus, confirmed.
This does not mean anyone is going to work on fixing this. Please, if
you are using this feature and would like to see this warning in GCC,
please consider contributing it:
https://gcc.gnu.org/wiki/GettingStarted#Basics:_Contributing_to_GCC_in_10_easy_steps
If you start working on this, it would be good to say so here.
I'm reading a bit of code in C, and in the variable declaration line, there's "char *p, *getenv();"
I understand "char *p" of course. What does "char *getenv()" do? Later on in the code, the function getenv() is called with a variable passed to it. But what's the point of "char *getenv();" without any arguments?
Sorry if this is basic. I'm just starting to learn C.
It is "valid C" (I would almost say "unfortunately") - but it is not particularly useful. It is a "declaration without declaration" - "I will be using a function getenv() but I'm not going to tell you what the arguments will be". It does have the advantage of preventing a compiler warning / error - something that would normally be prevented with a "real" function prototype, for example by including the appropriate .h file (in this case, stdlib.h).
To clarify: the following code
#include <stdio.h>
int main(void) {
char *p;
p = getenv("PATH");
printf("the path is %s\n", p);
return 0;
}
will throw a compiler warning (and you should never ignore compiler warnings):
nonsense.c: In function ‘main’:
nonsense.c:5: warning: implicit declaration of function ‘getenv’
nonsense.c:5: warning: assignment makes pointer from integer without a cast
Either adding #include <stdlib.h> or the line you had above, will make the warning go away (even with -Wall -pedantic compiler flags). The compiler will know what to do with the return value - and it figures out the type of the arguments on the fly because it knows the type when it sees it.
And that is the key point: until you tell the compiler the type of the return value of the function it does not know what to do (it will assume int, and make appropriate conversions for the variable you are assigning to - this can be inappropriate. For example, a pointer is often bigger than an int, so information will be lost in the conversion.)
It's a declaration (an old-style one without a prototype, since the argument list is missing) for the function getenv. Aside from being arguably bad style to hide a function declaration alongside the declaration of an object like this, it's bad to omit the prototype and bad not to be using the standard headers (stdlib.h in this case) to get the declarations of standard functions.
please take a look at my codes below
#include <stdio.h>
void printOut()
{
static int i = 0;
if (i < 10)
{
printOut(i);
}
}
int main(int argc, char *argv[])
{
return 0;
}
i guess there should be an error due to my invoking the non-existed function prototype.Actually, the code compiles well with mingw5 compiler, which is weird for me, then i change to Borland Compiler, i get a warning message said that no printOut function prototype, is this only a warning ? What is more, the code executes well without any pop-up error windows.
In C, a function without any parameters can still take parameters.
That's why it compiles. The way to specify that it doesn't take any parameters is:
void printOut(void)
This is the proper way to do, but is less common especially for those from a C++ background.
Your program's behavior is undefined, because you define printOut() with no parameters, but you call it with one argument. You need to fix it. But you've written it in such a way that the compiler isn't required to diagnose the problem. (gcc, for example, doesn't warn about the parameter mismatch, even with -std=c99 -pedantic -Wall -Wextra -O3.)
The reasons for this are historical.
Pre-ANSI C (prior to 1989) didn't have prototypes; function declarations could not specify the expected type or number of arguments. Function definition, on the other hand, specified the function's parameters, but not in a way that the compiler could use to diagnose mismatched calls. For example, a function with one int parameter might be declared (say, in a header file) like this:
int plus_one();
and defined (say, in the corresponding .c file) like this:
int plus_one(n)
int n;
{
return n + 1;
}
The parameter information was buried inside the definition.
ANSI C added prototypes, so the above could written like this:
int plus_one(int n);
int plus_one(int n)
{
return n + 1;
}
But the language continued to support the old-style declarations and definitions, so as not to break existing code. Even the upcoming C201X standard still permits pre-ANSI function declarations and definitions, though they've been obsolescent for 22 years now.
In your definition:
void printOut()
{
...
}
you're using an old-style function definition. It says that printOut has no parameters -- but it doesn't let the compiler warn you if you call it incorrectly. Inside your function you call it with one argument. The behavior of this call is undefined. It could quietly ignore the extraneous argument -- or it could conceivably corrupt the stack and cause your program to die horribly. (The latter is unlikely; for historical reasons, most C calling conventions are tolerant of such errors.)
If you want your printOut() function to have no parameters and you want the compiler to complain if you call it incorrectly, define it as:
void printOut(void)
{
...
}
This is the one and only correct way to write it in C.
Of course if you simply make this change in your program and then add a call to printOut() in main(), you'll have an infinite recursive loop on your hands. You probably want printOUt() to take an int argument:
void printOut(int n)
{
...
}
As it happens, C++ has different rules. C++ was derived from C, but with less concern for backward compatibility. When Stroustrup added prototypes to C++, he dropped old-style declarations altogether. Since there was no need for a special-case void marker for parameterless functions, void printOut() in C++ says explicitly that printOut has no parameters, and a call with arguments is an error. C++ also permits void printOut(void) for compatibility with C, but that's probably not used very often (it's rarely useful to write code that's both valid C and valid C++.) C and C++ are two different languages; you should follow the rules for whichever language you're using.
#include<stdio.h>
int f();
int main()
{
f(1);
f(1,2);
f(1,2,3);
}
f(int i,int j,int k)
{
printf("%d %d %d",i,j,k);
}
it is running fine(without any error) ...can u plz explain how it executes ?
how f(1) and f(1,2) links to f(int,int,int) ?
You must have a different definition of "error" to me :-) What gets printed the first two times you call your f function? I get
1 -1216175936 134513787
1 2 134513787
1 2 3
for my three function calls.
What you're seeing is a holdover from the very early days of C when people played footloose and fancy-free with their function calls.
All that is happening is that you are calling a function f and it's printing out three values from the stack (yes, even when you only give it one or two). What happens when you don't provide enough is that your program will most likely just use what was there anyway, usually leading to data issues when reading and catastrophic failure when writing.
This is perfectly compilable, though very unwise, C. And I mean that in a very real, "undefined behaviour", sense of the word (referring specifically to C99: "If the expression that denotes the called function has a type that does not include a prototype, ... if the number of arguments does not equal the number of parameters, the behaviour is undefined").
You should really provide fully formed function prototypes such as:
void f(int,int,int);
to ensure your compiler picks up this problem, and use ellipses (...) in variable parameter functions.
As an aside, what usually happens under the covers is that the calling function starts with a stack like:
12345678
11111111
and pushes (for example) two values onto a stack, so that it ends up like:
12345678
11111111
2
1
When the called function uses the first three values on the stack (since that's what it wants), it finds that it has 1, 2 and 11111111.
It does what it has to do then returns and the calling function clears those two values off the stack (this is called a caller-makes-good strategy). Woe betide anyone who tries this with a callee-makes-good strategy :-) although that's pretty unusual in C since it makes variable argument functions like printf a little hard to do.
This declaration:
int f();
...tells the compiler "f is a function that takes some fixed number of arguments, and returns int". You then try to call it with one, two and three arguments - C compilers are conceptually one-pass (after preprocessing), so at this point, the compiler doesn't have the information available to argue with you.
Your actual implementation of f() takes three int arguments, so the calls which only provide one and two arguments invoke undefined behaviour - it's an error which means that the compiler isn't required to give you an error message, and anything could happen when you run the program.
int f();
In C this declares a function which take a variable number of arguments i.e. it's equivalent to the following in C++
int f(...);
To check this use the following instead of int f();
int f(void);
This will cause the compiler to complain.
Please note: A C linker quirk is also involved here...the C linker does not validate the arguments being passed to a function at the point of invocation and simply links to the first public symbol with the same name. Thus the use of f() in main is allowed because of the declaration of int f(). But the linker binds the function f(int, int, int) during link time at the invocation sites. Hope that makes some sense (please let me know if it doesn't)
It runs fine since int f() means what other answer has already said: it means unspecified number of arguments. This mean you can call it with the number of arguments that you want (also more than 3), without the compiler saying anything about it.
The reason why it works "under the cover", is that arguments are pushed on the stack, and then accessed "from" the stack in the f function. If you pass 0 arguments, the i, j, k of the function "corresponds" to values on the stack that, from the function PoV, are garbage. Nonetheless you can access their values. If you pass 1 argument, one of the three i j k accesses the value, the others get garbage. And so on.
Notice that the same reasoning works if the arguments are passed in some other way, but anyway these are the convention in use. Another important aspect of these conventions is that the callee is not responsible for adjusting the stack; it is up to the caller, that knows how many argument are pushed for real. If it would be not so, the definition of f could suggest that it has to "adjust" the stack to "release" three integer, and this would cause a crash of some kind.
What you've written is fine for the current standard (on gcc compiles with no warnings even with -std=c99 -pedantic; there's a warning, but it's about the missing int in front of the f definition), even though many people finds it disgusting and call that an "obsolescent feature". For sure, your usage in the example code does not show any usefulness, and likely it can help busting bugs a more binding usage of prototypes! (But still, I prefer C to Ada)
add
A more "useful" usage of the "feature" that does not trigger the "undefined behaviour" issue, could be
#include<stdio.h>
int f();
int main()
{
f(1);
f(2,2);
f(3,2,3);
}
int f(int i,int j,int k)
{
if ( i == 1 ) printf("%d\n", i);
if ( i == 2 ) printf("%d %d\n", i, j);
if ( i == 3 ) printf("%d %d %d\n", i, j, k);
}
When you compile the same program using g++ compiler you see the following errors -
g++ program.c
program.c: In function `int main()':
program.c:2: error: too many arguments to function `int f()'
program.c:6: error: at this point in file
program.c:2: error: too many arguments to function `int f()'
program.c:7: error: at this point in file
program.c:2: error: too many arguments to function `int f()'
program.c:8: error: at this point in file
program.c: At global scope:
program.c:12: error: ISO C++ forbids declaration of `f' with no type
Using gcc with option -std=c99 just gives a warning
Compile the same program with the same standard which g++ is having by default, gives the following message:
gcc program.c -std=c++98
cc1: warning: command line option "-std=c++98" is valid for C++/ObjC++ but not for C
My answer then would be or c compilers conform to a different standard which is not as restrictive as the one which c++ conforms to.
In C a declaration has to declare at least the return type. So
int f();
declares a function that returns the type int. This declaration doesn't include any information about the parameters the function takes. The definition of the function is
f(int i,int j,int k)
{
printf("%d %d %d",i,j,k);
}
Now it is known, that the function takes three ints. If you call the function with arguments that are different from the definition you will not get a compile-time error, but a runtime error (or if you don't like the negative connotation of error: "undefined behavior"). A C-compiler is not forced by the standard to catch those inconsistencies.
To prevent those errors, you should use proper function prototypes such as
f(int,int,int); //in your case
f(void); //if you have no parameters