Why don't ANSI C compilers flag the use of a string literal argument in a function call in which the correponding parameter does not have a const qualifier? For example, the following code could generate an exception by trying to write to read only memory.
void somefunc(char buffer[10]);
void somefunc(char buffer[10]) {
int i;
for (i = 0; i < 10; i++)
buffer[i] = 0;
}
int main(int argc, char **argv) {
somefunc("Literal");
return 0;
}
This situation could be identified at compile time but VS2010 and gcc don't appear to do so. Calling somefunc with a const char* argument will generate a compiler warning.
It is a K&R legacy. Fixing it would break a million programs.
gcc: Use the flag -Wwrite-strings
PS. gcc manual explains why this isn't part of -Wall. Anyway, as always, you should find a combination of -W flags that suits your particular needs and coding style. For example, in a recent project I have used something like this: -Werror -Wall -Wextra -Wformat=2 -Winit-self -Wswitch-enum -Wstrict-aliasing=2 -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wdisabled-optimization -Wunused-macros -Wno-unused
What Hans Passant said. const was added as part of the ANSI standard on 1989, so anything from before that didn't have const.
string literals are not const in C; in C++ they are.
edit: to clear up any confusion about my comment, I am referring to the type, not the ability to actually change them.
The GNU compiler (and the Intel C compiler as well, iirc) will emit a warning, if -Wwrite-string is used:
$ gcc -Wall -Wwrite-strings -o foo /tmp/foo.c
/tmp/foo.c: In function 'main':
/tmp/foo.c:12: warning: passing argument 1 of 'somefunc' discards qualifiers from pointer target type
/tmp/foo.c:3: note: expected 'char *' but argument is of type 'const char *'
Concerning VS2010, I can't help you.
Related
I want to show that arrays can't be defined with a variable for the length in C89 or C90.
I use GCC on Windows from TDM GCC:
C:\TDM-GCC-64\bin> .\gcc.exe --version
gcc.exe (tdm64-1) 10.3.0
My compilation options are:
gcc.exe -Wall -g -ansi -save-temps -c
I tried:
int main()
{
int i;
int tab[i];
tab[0] = 10;
return 0;
}
But it compiles fine:
gcc.exe -Wall -g -ansi -save-temps -c main.c -o main.o
gcc.exe -o Sandbox.exe main.o
main.c:6:9: warning: variable 'tab' set but not used [-Wunused-but-set-variable]
6 | int tab[i];
| ^~~
main.c:6:5: warning: 'i' is used uninitialized in this function [-Wuninitialized]
6 | int tab[i];
| ^~~
Output file is bin\Debug\Sandbox.exe with size 196.89 KB
Then:
int test(int i)
{
int tab[i];
tab[0] = 10;
return 0;
}
Compiles too:
main.c: In function 'test':
main.c:5:9: warning: variable 'tab' set but not used [-Wunused-but-set-variable]
5 | int tab[i];
| ^~~
Output file is bin\Debug\Sandbox.exe with size 196.90 KB
Or:
int main()
{
volatile int i;
int tab[i];
tab[0] = 10;
return 0;
}
Only this is not compiling:
int main()
{
// Comment
return 0;
}
error: C++ style comments are not allowed in ISO C90
What am I missing?
Thanks!
Variable length array is a GCC extension in older standard versions. Extensions are "compatible" with the standard. If you want to exactly adhere to the standard, i.e. you want to get a message when using an extension, add -pedantic option (and -pedantic-errors for errors).
Gcc docs: https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Variable-Length.html#Variable-Length , https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Warning-Options.html#Warning-Options .
gcc has sloppy standard compliance per default. It defaults to lax C conformance + GNU extensions, equivalent to -std=gnu89 (current version defaults to -std=gnu17).
When you type -ansi it does not mean conforming mode, but rather just the very same thing as -std=c89, "lax C89 mode". This compiler option may disable some GNU extensions... maybe... while keeping others. The difference between -std=c89 and -std=gnu89 is as poorly documented as the rest of gcc. We can read the unfriendly manual and it says:
For example, -std=c90 turns off certain features of GCC that are incompatible with ISO C90, such as the asm and typeof keywords, but not other GNU extensions that do not have a meaning in ISO C90
gcc supported variable-length arrays as an extensions even before C99, so switching out the GNU option ought to disable them, but not so... As far as I know, there is no official documentation over what features -std=c89 shuts off or at least I can't find it.
What's important to realize is that -std=c89/-ansi alone does not push gcc into conforming mode! To do that, you need to do -std=c89 -pedantic or if you will -std=c89 -pedantic-errors. After which you'll get a diagnostic like this:
error: ISO C90 forbids variable length array 'tab'
And when compiling with these two options in combination, gcc probably has the best standard compliance of any compiler out there.
How can i suppress this warning?
maybe some #pragma GCC diagnostic ignored in code or CFLAG in makefile?
If you had posted the full warning message it should show the specific warning [-Wdiscarded-qualifiers]. Like other warnings, just prefix with no- to suppress it.
From the gcc manual
-Wno-discarded-qualifiers (C and Objective-C only)
Do not warn if type qualifiers on pointers are being discarded. Typically, the compiler warns if a const char * variable is passed to a function that takes a char * parameter. This option can be used to suppress such a warning.
$ cat test.c
#include <stdio.h>
int a;
volatile int *p = &a;
int main (void)
{
int *q = p;
return 0;
}
$ gcc test.c
test.c: In function ‘main’:
test.c:8:11: warning: initialization discards ‘volatile’ qualifier from pointer target type [-Wdiscarded-qualifiers]
int *q = p;
^
$ gcc -Wno-discarded-qualifiers test.c
$
Although you probably already know it is a bad programming tactic, you can disable warnings in general when compiling and not only the one that bugs you.
Add -w option when compiling
I also attach you the documentation on Warnings Options.
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Hope i helped!
ok thanks guys. -Wdiscarded-qualifiers not really helped me.
actually ive tried to find it in gcc docs, but i am not good at this.
here`s my cflags in project
CFLAGS ?= -g0 -O3 -Wno-discarded-qualifiers -Wshadow -Wmaybe-uninitialized -Wall -Wextra -Wno-unused-function -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wno-switch-enum -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body -Wtype-limits -Wno-unused-value -Wno-unused-parameter -Wno-missing-field-initializers -Wuninitialized -Wmaybe-uninitialized -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wpointer-arith -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-sign-compare
LDFLAGS ?= -lm
and the reason that i am using discard volatile qualifiers is that i dont want to add volatile in function prototypes and dont want to cast it in function call, because some of variables works fine without volatile key, and others - not.
(its some common variables and also thread_t types)
so code works fine, also when ive tried to cast volatile types in function call - there some glitches happened, and now all works fine. Thanks for help i appreciate that!
now with that key i have
"discards 'volatile' qualifier from pointer target type"
its pointers that sometimes get optimizated by compiler.
I recently came across the following warning in one of my applications that uses the GLib:
warning: ISO C prohibits argument conversion to union type [-Wpedantic]
note: in definition of macro '_G_DEFINE_BOXED_TYPE_BEGIN'
2147 | _g_register_boxed (g_intern_static_string (#TypeName), copy_func, free_func);
I usually compile with -wpedantic and it was the first time for me to get a warning that couldn't be traced down to my code, but seems to be caused by the internals of the _G_DEFINE_BOXED_TYPE_BEGIN-macro. The warning seems to appear whenever G_DEFINE_BOXED_TYPE is used with a dedicated free or copy function.
An example application may look as the following:
/* boxed_warning.c
* Produces warning, when compiled with:
* $ cc `pkg-config --cflags glib-2.0` -Wextra -Wpedantic -Wall -std=gnu11 -O0 -g -o 'boxed_warning.c.o' -c boxed_warning.c
*/
#include <glib.h>
#include <gio/gio.h>
struct _FooBoxed { gdouble x; };
typedef struct _FooBoxed FooBoxed;
static FooBoxed *
foo_boxed_copy (const FooBoxed *boxed)
{
FooBoxed *result = g_new (FooBoxed, 1);
*result = *boxed;
return result;
}
G_DEFINE_BOXED_TYPE (FooBoxed, foo_boxed, (GBoxedCopyFunc) foo_boxed_copy, (GBoxedFreeFunc) g_free)
I'm using glib 2.62.4, but I can reproduce the warning even when compiling with the latest version from git.gnome.org.
Has anyone else experienced this warning when working with the GLib2.0 and found a work-around? Or is the warning indeed related to a wrong usage of the mentioned macro by my code?
I created a basic C project in Xcode and modified the starter code in main.c slightly. I also went into the build settings and told it to use ANSI-C. Here's the code I have:
int main(int argc, const char * argv[])
{
// a statement!
printf("Hello, World!\n");
// shouldn't this cause a compiler error?
// the variable isn't declared at the top of the scope.
int x;
x += 10;
return 0;
}
Obviously, it doesn't do much, but I expected the variable declaration to produce a compiler error (since older versions of C require variable declarations at the beginning of the scope, before other statements). However, Xcode happily compiles it and runs it with neither an error or warning.
I might be making a dumb mistake somewhere, but I'm trying to understand why this code compiles. I've read that C99 and C11 allow you to declare variables anywhere, so this would work, but I explicitly set the project to use ANSI-C. Is this just the way Apple's LLVM compiler works? Or am I missing something elsewhere?
TL;DR You need to add -pedantic (or -Wdeclaration-after-statement) to -ansi to get the warning you want.
Somewhat to my surprise, both clang (from Apple XCode 7.2) and gcc (from GCC 5.3.0, which I built), accept the code when compiled with either -std=c90 or -ansi even though it is not strictly compliant with C90.
However, both complain when told to be -pedantic.
$ clang -ansi -c xyz.c
$ clang -std=c90 -c xyz.c
$ gcc -std=c90 -c xyz.c
$ which gcc
/opt/gcc/v5.3.0/bin/gcc
$ gcc -std=c90 -pedantic -c xyz.c
xyz.c: In function ‘main’:
xyz.c:7:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
int x;
^
$ clang -pedantic -std=c90 -c xyz.c
xyz.c:7:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
int x;
^
1 warning generated.
$ clang -pedantic -ansi -c xyz.c
xyz.c:7:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
int x;
^
1 warning generated.
$
The file xyz.c is your source code with the comments stripped, #include <stdio.h> added at the top, and int main(void) in place of int main(int argc, char **argv) since the code doesn't use the arguments.
Note that your code has undefined behaviour; incrementing an uninitialized variable is a bad idea.
I’m using the following flags, but still I m not able to get this warning:
pointer of type void * used in arithmetic
Flags used:
-O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -Wno-sign-compare -Wno-pointer-sign -Wno-attributes -fno-strict-aliasing
-Wpointer-arith should catch this type of warning, but I’m not able to get this warning:
pointer of type void * used in arithmetic
Which specific cflag should be used to get this warning?
Edit: my mistake, it is there as part of a macro check which is not defined. :( By defining that macro, I’m able to get that error.
You're right. -Wpointer-arith should give you a warning as per the documentation.
I have just tried the following program (with intentional error):
~/code/samples$ cat foo.c
#include <stdio.h>
int main (int argc, char **argv)
{
void * bar;
void * foo;
foo = bar + 1;
return 0;
}
I have compiled the program with just the -Wpointer-arith option, and all your options as listed above. Both attempts threw up the desired warning. I am using gcc version 4.3.4 (Debian 4.3.4-6).:
~/code/samples$ gcc -Wpointer-arith foo.c
foo.c: In function ‘main’:
foo.c:6: warning: pointer of type ‘void *’ used in arithmetic
and
~/code/samples$ gcc -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -Wno-sign-compare -Wno-pointer-sign -Wno-attributes -fno-strict-aliasing foo.c
cc1: warnings being treated as errors
foo.c: In function ‘main’:
foo.c:6: error: pointer of type ‘void *’ used in arithmetic
The compiler does throw up the warning if you give it the 'right' code. So, I would recommend you examine why it is you expect this warning. Maybe the code you're compiling has changed?
One possible clue I can give you: foo = bar + 1; in the code above triggers the warning. But foo = bar ++; will not (You get a different warning). So if your code uses increment (or decrement) operators on pointers, it will probably not trigger the warning.
I know this is not a direct answer, but I hope this helps you focus your investigation.
With gcc 4.2.1 on OS X, I get this warning:
p.c:7: warning: wrong type argument to increment
for the following program:
#include <stdio.h>
int main(void)
{
int i[] = { 42 };
void *p = i;
printf("%p\n", p++);
return 0;
}
I am compiling it as:
$ gcc -Wpointer-arith p.c
Can you post your program, or post the result of compiling the above?