clang issue: inline function inside another function body in C - c

It is challenging to port from Linux to OS/X. I have an inline function embedded inside another function body. On Linux, gcc happily compiled the code, but on OS/X, clang reports error.
Here is the code snippet,
$ cat inline.c
void func() {
inline int max(int a, int b) { return (a>b) ? a : b; }
int c = max(11,22);
}
On Linux, everything is fine,
Linux $ gcc -c inline.c
Linux $$ gcc --version
gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010
However, clang on OS/X complains,
OSX $ cc -c inline.c
inline.c:2:38: error: function definition is not allowed here
inline int max(int a, int b) { return (a>b) ? a : b; }
^
inline.c:3:17: warning: implicit declaration of function 'max' is invalid in C99
[-Wimplicit-function-declaration]
int c = max(11,22);
^
1 warning and 1 error generated.
OSX $ cc --version
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.5.0
Is this a gcc "feature" or there is a clang flag to enable this capability?

GCC extensions not implemented yet
clang does not support nested functions; this is a complex feature which is infrequently used, so it is unlikely to be implemented anytime soon.
Just move the max out the function and make it static.

Here, "inline" means "inline substitution", rather than "inline definition".
According to N1570:
6 A function declared with an inline function specifier is an inline
function. Making a function an inline function suggests that calls to
the function be as fast as possible.138) The extent to
which such suggestions are effective is
implementation-defined.139)
138) By using, for example, an alternative to the usual function
call mechanism, such as ''inline substitution''. ...
And you shouldn't define another function in a function definition. Also, use static inline instead of inline would make your life easier.

Related

ccosl undeclared when trying to use cos(double) from tgmath.h on arm-none-eabi-gcc

Consider the following test code:
#include <tgmath.h>
void test()
{
double x=cos(4.5);
}
Compiling it as with
arm-none-eabi-gcc test.c -c
on Ubuntu 18.04 (gcc 6.3.1, newlib 2.4.0) works fine, but on Ubuntu 20.04 (gcc 9.2.1, newlib 3.3.0) I get the following errors:
In file included from test.c:1:
test.c: In function 'test':
test.c:5:14: error: 'ccosl' undeclared (first use in this function); did you mean 'ccosh'?
5 | double x=cos(4.5);
| ^~~
test.c:5:14: note: each undeclared identifier is reported only once for each function it appears in
test.c:5:14: error: argument 6 of '__builtin_tgmath' is not a function pointer
Apparently, the definition of cos has somehow changed, so that it now mentions ccosl which is not declared anywhere.
If I change from tgmath.h to math.h, the error no longer appears. This is of course just a workaround, not a fix, since this way I lose the type genericity for float vs double.
My question is: how do I make it work properly? Do I have to add some compilation option, or is it just a bug in the toolchain?
It appears that the difference between the versions of the toolchains is in the GCC implementation of tgmath cos macro in different versions. Namely, compiling with -E option for gcc yields the following (cleaned up) expansion of double x=cos(4.5) in 6.3.1:
double x=__builtin_choose_expr(__builtin_classify_type(4.5) == 9,
__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(__real__(4.5)), long double),
ccosl(4.5),
__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(__real__(4.5)), double) || __builtin_classify_type(__real__(4.5)) == 1,
ccos(4.5),
ccosf(4.5))
),
__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(4.5), long double),
cosl(4.5),
__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(4.5), double) || __builtin_classify_type(4.5) == 1,
cos(4.5),
cosf(4.5))
)
);
while in GCC 9.3.0 the expansion is as a simple function call:
double x=__builtin_tgmath (cosf, cos, cosl, ccosf, ccos, ccosl, 4.5);
The main difference between the two is that __builtin_choose_expr doesn't evaluate the expression that is not chosen (as said in the docs), while __builtin_tgmath is a function, which needs all the arguments to be valid.
And it looks like newlib has never had ccosl in its complex.h, so it appears incompatible with the newer version of GCC.

Telling gcc to fail to compile when in pre-C99 mode

I am giving a lecture on the history of C, and would like to show some idioms that used to be impossible but now are (in particular, defining variables in the middle of the block). I would like to show that older C compilers wouldn't compile it.
gcc has the -std= option for setting the language standard. Unfortunately, setting it for -std=c89 does not produce compilation errors on defining variables in the middle of a block.
I was hoping for a more accurate std version (i.e. - -std=knr), but I could not find any such option.
Am I missing something? Is this a bug in GCC?
gcc (Ubuntu 8.2.0-7ubuntu1) 8.2.0
The code that erroneously compiles:
#include <stdio.h>
int main(argc, argv)
int argc;
char *argv[];
{
printf("Hello, world\n");
int a;
return 0;
}
If you want truly strict conformance to a -std flag, it should be accompanied by the -pedantic-errors flag.
As a demonstration, your code on wandbox with those flags produces:
prog.c: In function 'main':
prog.c:9:9: error: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
int a;
^~~

Inline function with assert creates an undefined reference? [duplicate]

This question already has answers here:
Is "inline" without "static" or "extern" ever useful in C99?
(3 answers)
What does extern inline do?
(7 answers)
Closed 2 years ago.
divide.h
#pragma once
#include <assert.h>
inline int divide(int a, int b)
{
assert(b != 0);
return a / b;
}
main.c
#include <divide.h>
int main(void)
{
divide(10, 2);
return 0;
}
I am unable to compile the following solely because of the assert. If I remove the assert, everything works fine.
$ gcc --version
gcc (GCC) 8.1.0
$ gcc main.c
main.c:(.text+0xf): undefined reference to `divide'
$ gcc main.c -O3 # Compilation with optimization works as asserts are removed.
When placing the defintion of divide inside a .c file, everything works fine. However, shouldn't the following also work since the function is declared as inline?
The C99 standard says this about inline functions in 6.7.4 "Function specifiers":
An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.
So an implementation can choose to not inline a function call in which case there needs to be an external definition of the function. I'd guess that since the assert is a debugging tool, GCC doesn't want to inline functions that have active asserts to aid in debugging.

How to compile C code with C headers and CUDA code?

I have a main code wich uses some libraries and I been compiling it like this:
gcc importedCFile1.c importedCFile2.c mainCode.c -O3 -lm -Wall -o maincode -lrt
Now I have added CUDA code in mainCode and changed its extension to .cu... So, how can I compile the whole thing?
I tried:
nvcc importedCFile1.c importedCFile2.c mainCode.cu -o maincode
but I got a lot of "undefined reference" to my functions in the imported C files.
To include my C files I am using:
extern "C" {
#include "importedCFile1.h"
#include "importedCFile2.h"
}
And ´importedCFile1.c´ is using some functions and variables declared in ´importedCFile2.c´ and ´mainCode.cu´. Like this:
extern int **se; // Variables from mainCode
extern int *n;
extern int numNodes;
extern int *getVector(int n); // Function from mainCode
extern int iRand(int high); // Function from importedCFile2
This functions are the cause of the undefined references. What should I do?
Also, how do I add the flags I need for the C code, such as -lrt, O3, lm and Wall??
EDIT: You can find a reduced example of the problem here:
https://github.com/mvnarvaezt/cuda/tree/master/minimalExample
If you compile the mainCode.c and importedCFile.c with gcc it works fine. If you compile mainCode.cu and importedCFile.c with nvcc you will get an undefined reference to anExample() (the function in importedCFile.c).
And you comment the header importing importedCFile.c and the call to anExampled() function it would work find.
Your problem is that the C code in importedFile.c is trying to call back C++ functions in mainCode.cu.
In order to be callable from C, C++ functions must have C linkage. Declare getVector() as
extern "C" int *getVector(int n) {
in mainCode.cu, and your example will compile fine.

How to enforce the usage of return values in C

I'm searching for a compiler flag for gcc and if possible for clang and the Microsoft compilers as well, that triggers a warning (error with -Werror) if a non-void function is called without using the return value like this:
int test() {
return 4;
}
int main(void) {
test(); //should trigger a warning
int number = test(); //shouldn't trigger the warning
return 0;
}
If there is no such compiler flag, maybe some way to tell the clang static analyzer to complain about it.
EDIT: To clarify my original question: I actually meant using the return value, not only assigning it.
I never used it myself (do you really need it?), you can try
defining the function with warn_unused_result attribute
enabling -Wunused-result flag with gcc.
This will tell you about any unused value from the function return.
In case, any doubts, SEE IT LIVE or SEE IT LIVE AGAIN Thanks to M.M for the link in the comment
Or:
#include <stdio.h>
extern int func1(void) __attribute__((warn_unused_result));
extern int func2(void);
int main(void)
{
func1();
int rc1 = func1();
int rc2 = func1();
func2();
printf("%d\n", rc1);
return 0;
}
Compilation (GCC 5.1.0 on Mac OS X 10.10.5):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -c warn.c
warn.c: In function ‘main’:
warn.c:10:9: error: unused variable ‘rc2’ [-Werror=unused-variable]
int rc2 = func1();
^
warn.c:8:5: error: ignoring return value of ‘func1’, declared with attribute warn_unused_result [-Werror=unused-result]
func1();
^
cc1: all warnings being treated as errors
$
Some static code analyzers like splint can check for these kind of things:
$ splint check.c
Splint 3.1.2 --- 03 May 2009
check.c: (in function main)
check.c:6:5: Return value (type int) ignored: test()
Result returned by function call is not used. If this is intended, can cast
result to (void) to eliminate message. (Use -retvalint to inhibit warning)
Unlike #Sourav's answer, this does not require a specific __attribute__ annotation on the target function, but on the other hand possibly emits many warnings. Its usually possible to suppress the warnings for specific functions or function calls by using annotations (like /*#alt void#*/).

Resources