I recently had to type in a small C test program and, in the process, I made a spelling mistake in the main function by accidentally using vooid instead of void.
And yet it still worked.
Reducing it down to its smallest complete version, I ended up with:
int main (vooid) {
return 42;
}
This does indeed compile (gcc -Wall -o myprog myprog.c) and, when run, it returns 42.
How exactly is this valid code?
Here's a transcript cut and pasted from my bash shell to show what I'm doing:
pax$ cat qq.c
int main (vooid) {
return 42;
}
pax$ rm qq ; gcc -Wall -o qq qq.c ; ./qq
pax$ echo $?
42
It's simply using the "old-style" function-declaration syntax; you're implicitly declaring an int parameter called vooid.
It's valid code, because myprog.c contains:
int main (vooid) // vooid is of type int, allowed, and an alias for argc
{
return 42; // The answer to the Ultimate Question
}
vooid contains one plus the number of arguments passed (i.e., argc). So, in effect all you've done is to rename argc to vooid.
In C, the default type for a function argument is int. So, your program is treating the word vooid as int main(int vooid), which is perfectly valid code.
It is only gcc -std=c89 -Wall -o qq qq.c and gcc -std=gnu89 -Wall -o qq qq.c don't emit a warning. All the other standards emit a warning about implicit type int for vooid.
int main(chart) behaves the same way as does int main (vooid).
return vooid; returns the number of command line arguments.
I tested with gcc 4.4.5 on Debian testing system.
Related
I'm trying to implement a simple integration of R with C. Initially it's simple: I want to pass values from R to a C function built into a .o shared library via .C or .Call function. The C function should simply print the values passed in via printf.
Here's my .Call method:
.Call("test", as.integer(5), as.character("A"), as.character("string_test"))
And my C code:
#include <stdio.h>
void test(int integer, char character, char **str) {
printf("Integer: %i\nChar: %c\nString: %s\n", integer, character, *str);
}
But when I call the C function from R via console (RStudio crashes) with gdb enabled, I receive:
Integer: 1466480376
Char: �
Float: -100407552.000000
String:
***caught segfault ***
address 0x20000090, cause 'memory not mapped'
Traceback:
1: .Call("test", as.integer(5), as.character("A"), as.character("string_test"))
As if it were not enough, as we can see the values passed in are printed very strangely.
Details of what I did, step by step:
I built the .o shared library with gcc:
gcc -shared -o func_teste.o -fPIC func_teste.c
And prepared it for dynamic loading in R environment:
$ R CMD SHLIB func_teste.o
gcc -m64 -I/usr/include/R -DNDEBUG -I/usr/local/include -fpic -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -c func_teste.c -o func_teste.o
gcc -m64 -shared -L/usr/lib64/R/lib -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -o func_teste.so func_teste.o -L/usr/lib64/R/lib -lR
And finally, inside R console, i ran:
>dyn.load('func_teste.o')
>.Call("test", as.integer(5), as.character("A"), as.character("string_test"))
Does anyone have idea why this is happening?
R offers two main functions for interfacing from C code (and hence C++ code, or any other language able to use a C interface):
- .C() is the older interface using int*, double*, ... and alike
- .Call() is the newer, more powerful interface using SEXP objects
Now, .Call() looks more complicated but it is so much more powerful as well as safer. There is near universal consensus that .C() should no longer be used (see various discussions on the r-devel list and other places).
The main downside with .Call() is that you need to learn how to pack and unpack your values. Or ... you cheat and let Rcpp do it for you. So with that, here is one-line solution of the OP's example:
> library(Rcpp)
> cppFunction("void mytest(int i, char c, std::string str) { printf(\"Integer: %i Char: %c String: %s\\n\", i, c, str.c_str()); }")
> mytest(42L, 'Q', "a boat")
Integer: 42 Char: Q String: a boat
>
I made the char* a string. Note that cppFunction() requires escaping of strings, you may want to look into sourceCpp() and packages for real work. The Rcpp documentation has details.
Don't as.character on "string_test".
Read more here: http://mazamascience.com/WorkingWithData/?p=1067
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.
Here is my program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
char errbuf[256];
errno = 0;
strtoul("99999999999999999999999999999999999999999999", NULL, 0);
strerror_r(errno, errbuf, sizeof errbuf);
printf("strerror_r: %s\n", errbuf);
return 0;
}
When I compile it with -std=gnu90 or -std=gnu99, I get the expected output.
susam#nifty:~/lab/linux$ rm -f a.out && gcc -std=gnu90 -Wall -Wextra -pedantic foo.c && ./a.out
strerror_r: Numerical result out of range
susam#nifty:~/lab/linux$ rm -f a.out && gcc -std=gnu99 -Wall -Wextra -pedantic foo.c && ./a.out
strerror_r: Numerical result out of range
But when I compile it with -std=c90 or -std=c99, I get a warning and I don't see strerror_r putting the string in errbuf.
lone#debian:~/lab/linux$ rm -f a.out && gcc -std=c90 -Wall -Wextra -pedantic foo.c && ./a.out
foo.c: In function ‘main’:
foo.c:12:2: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration]
strerror_r(errno, errbuf, sizeof errbuf);
^
strerror_r:
lone#debian:~/lab/linux$ rm -f a.out && gcc -std=c99 -Wall -Wextra -pedantic foo.c && ./a.out
foo.c: In function ‘main’:
foo.c:12:2: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration]
strerror_r(errno, errbuf, sizeof errbuf);
^
strerror_r:
What is going wrong when I use -std=c90 or -std=c99?
With -std=c89 you ask the implementation to provide exclusively the declarations for identifiers part of ISO 9899:1989. The identifier strerror_r is not part of C89 (or C99), so there is no prototype. In consequence you get the warning about an implicit declaration.
If you look at the relevant header you will likely find the strerror_r prototype buried in a maze of #ifdefs. The -std option changes the set of pre-defined macros affecting the visibility of the prototype.
strerror_r(3) says:
The XSI-compliant strerror_r() is preferred for portable applications. It returns the error string in the user-supplied buffer buf of length buflen.
The GNU-specific strerror_r() returns a pointer to a string containing the error message. This may be either a pointer to a string that the function stores in buf, or a pointer to some (immutable) static string (in which case buf is unused). If the function stores a string in buf, then at most buflen bytes are stored (the string may be truncated if buflen is too small and errnum is unknown). The string always includes a terminating null byte.
So it's not just a matter of whether the declaration is visible or not (which is a pretty big problem by itself - when you get an "Implicit declaration" warning, you shouldn't expect the program to work at all.) It's also a question of which version of the function you're calling. The GNU version sometimes returns a pointer to a constant string in the library instead of copying the string to the caller-supplied buffer.
The basic purpose of strerror_r isn't "I want the string in this buffer"; it's "I want a string that won't be overwritten by the library later."
I'm new to C and stuck on this. The answer here seems widely accepted, but I believe I'm following the correct format and still getting issues.
Here's the offending line in main() (in main.c)
PrintWrapper(PrintFunction, *decoded); // *decoded is a char
The PrintFunction (also in main.c):
void PrintFunction(char c)
{
printf("%c", c);
}
And the prototype declaration (in p1a2.h - in the same directory as main.c)
extern void PrintWrapper(void (*)(char), char c);
The actual source is hidden away in printwrapper.o (same directory as main.c). This is for an assignment and is a very contrived usage of passing a function as a parameter. I compile the program with
g++ main.c printwrapper.o -Wall -g -o tnine
and get the compiler error (the backtick is not a typo if that is relevant)
<path>/main.c:42: undefined reference to `PrintWrapper(void (*)(char), char'
Why does this happen? I'm hoping it's me overlooking something simple.
As you are using g++, the compiler expects the function name to be mangled (for more information see this wikipedia article.
To fix the issue, use gcc instead of g++ or try the following:
extern "C" void PrintWrapper(void (*)(char), char*);
The code you showed us is valid.
Looks like printwrapper.o just don't contain such function.
You should use gcc instead of g++ to compile C code. The latter front-end is for C++ code, which symbols are subject to name mangling. Assuming that you are really asking about C language, the proper way to compile your project is:
gcc main.c printwrapper.o -Wall -g -o tnine
Here is some working sample:
main.c
#include <stdio.h>
#include "pla2.h"
void PrintFunction(char c)
{
printf("%c\n", c);
}
int main(void)
{
char c = 'a';
char *decoded = &c;
PrintWrapper(PrintFunction, *decoded);
return 0;
}
pla2.h
extern void PrintWrapper(void (*)(char), char c);
printwrapper.c
extern void PrintWrapper(void (*f)(char), char c)
{
f(c);
}
then:
$ gcc -c printwrapper.c
$ gcc main.c printwrapper.o -Wall -g -o tnine
$ ./tnine
a
I was reading C programming from a book that says all variables have to be declared in the beginning of the function. I tried following code but didn't issue any error. I am using mingw and codeblocks. The code is as follows:
#include <stdio.h>
int main()
{
int i=10;
printf("%d\n",i);
int j=20;
printf("%d\n",j);
return 0;
}
Do I have to change any compiler setting or something to make it compatible with the standard given in the book?
I am using -std=c89 compiler option. See the compilation messages below:
-------------- Clean: Debug in HelloWorld (compiler: GNU GCC Compiler)---------------
Cleaned "HelloWorld - Debug"
-------------- Build: Debug in HelloWorld (compiler: GNU GCC Compiler)---------------
mingw32-gcc.exe -Wall -std=c89 -g -c D:\MyCodeBlocksProjects\HelloWorld\main.c -o obj\Debug\main.o
mingw32-g++.exe -o bin\Debug\HelloWorld.exe obj\Debug\main.o
Output size is 68.53 KB
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 0 warnings (0 minutes, 0 seconds)
all variables have to be declared in the beginning of the function.
To be precise, they have to be declared in the beginning of a block. And this is only true in C89. C99 has removed this limit. So you can change your compiler to strict C89 mode. For example, for GCC, it's -std=c89 option. To obtain all the diagnostics required by the standard, you should also specify the option -pedantic.
To demonstrate what I mean by in the beginning of a block, this is legal C89 syntax:
void foo()
{
int x = 1;
x = x + 1;
{
int y = 42; /**OK: declaration in the beginning of a block*/
}
}