I am working on a C project which has same definition of C function in multiple places. I am trying to get the definition of C function using compilation errors like "error: conflicting types for foo_func()"; which also provides header file declaration as "bar_file.h:< line no >: note: previous declaration of foo_func() was here". I want to rely on compilation error instead of grep like commands because compiler knows for sure which function it is linking with, so I can be sure of the function definition which is being used.
I am able to locate the header file with deliberately applying compilation error. Is there a way to use the similar technique to find the definition of function I am using at compilation time?
Example: Let's find the header file which has the declaration of the function we are using. We can end up into the following compilation error by purposeful introduction of multiple definition with a known parameter mismatch.
$ gcc -Wall -Wextra -c exmpl_01.c -I./
exmpl_01.c:5: error: conflicting types for ‘call_func_other_file’
exmpl_01.h:1: note: previous declaration of ‘call_func_other_file’ was here
$ head -4 exmpl_01.c
#include <stdio.h>
#include "exmpl_01.h"
int call_func(void);
int call_func_other_file(char *);
$ cat exmpl_01.h
int call_func_other_file(void);
You can try deliberately addind a duplicate definition in a separate translation unit. Then link all object files together (compiled with debugging symbols enabled). The linker will tell you in what file and on what line the duplicate is defined.
Maybe you are looking for -E switch ?
// a.h
int a() {
return 1;
}
and then, we have
// main.c
#include "a.h"
int main() {
return a();
}
and, with -E you can get
> gcc -E main.c
# 1 "main.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 331 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "main.c" 2
# 1 "./a.h" 1
int a() {
return 1;
}
# 2 "main.c" 2
int main() {
return a();
}
now, let's say our source has another file
// b.h
float a() {
return 1.0;
}
and main.c is slightly different
#include "a.h"
#include "b.h"
int main() {
return a();
}
you will be able to see the last definition of function
gcc -c -E main.c
# 1 "main.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 331 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "main.c" 2
# 1 "./a.h" 1
int a() {
return 1;
}
# 2 "main.c" 2
# 1 "./b.h" 1
float a() {
return 1.0;
}
# 3 "main.c" 2
int main() {
return a();
}
But, I am not sure whether this is something you are looking for ;)
Hmm ... if you want to stop at certain point, maybe this one will help you:
#include "a.h"
#include "b.h"
int main() {
a();
#error Quit!
printfun("aaa");
}
and this way, compilation will fail a #error
> gcc -c -Wfatal-errors main.c
In file included from main.c:2:
./b.h:1:7: fatal error: conflicting types for 'a'
float a() {
^
./a.h:1:5: note: previous definition is here
int a() {
^
1 error generated.
Or, you can simply introduce some sort of fake type
#include "a.h"
struct fake_type {
int fake_component;
};
struct fake_type *a();
int main() {
a();
}
and enforce the error
> gcc -c -Wfatal-errors main.c
main.c:7:19: fatal error: conflicting types for 'a'
struct fake_type *a();
^
./a.h:1:5: note: previous definition is here
int a() {
^
1 error generated.
Related
Is there a way to change the #include syntax? Here's an example of I am trying to reach out with this.
#define begin {
#define end }
#define import #include
import <stdio.h>
int main() begin
return 0;
end
Not really. At least not in a way that would fill any practical meaning.
First, the preprocessor is run and it till change "import" to "#include", and then it gives the output to the compiler. But the compiler does not understand preprocessor directives. Also, the C language does not have any functionality to include files. That's supposed to be handled by the preprocessor.
So one thing that CAN be done, although it's not something you should ever do in production code is to run the preprocessor twice. It's very likely that this approach will yield bugs that are tricky to find.
$ cat a.c
#define begin {
#define end }
#define import #include
import <stdio.h>
int main() begin
return 0;
end
$ gcc -E a.c > b.c
$ cat b.c
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "a.c"
#include <stdio.h>
int main() {
return 0;
}
$ gcc b.c
$
You could simplify the above to one command like this:
gcc -E a.c | gcc -xc -
(The final dash is important)
Per C 2018 6.10.3.4 3, after a macro has been substituted:
The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one,…
Thus, defining a macro to expand to #include will not result in an #include directive being processed.
I'm performing a header check for a non-standard <x86intrin.h> header provided by Clang and GCC. Other compilers follow Intel and use <immintrin.h>:
AC_CHECK_HEADER([x86intrin.h])
Autotools finds it on the Linux test systems:
checking x86intrin.h usability... yes
checking x86intrin.h presence... yes
checking for x86intrin.h... yes
I then use it in a test:
CXXFLAGS="-mrdseed"
XXX_PROGRAM="#include <immintrin.h>
#ifdef HAVE_X86INTRIN_H
# include <x86intrin.h>
#endif
int main(int argc, char** argv) {
unsigned int x;
return _rdseed32_step(&x);
}"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS])
AC_COMPILE_IFELSE(
[AC_LANG_SOURCE([$XXX_PROGRAM])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
The test fails:
checking if g++ supports -mrdseed... no
The machine has the feature and the compiler supports it. Looking at condefs.h from config.log shows HAVE_X86INTRIN_H is not being set as expected.
The manual shows how to use a header resulting from a check at 5.6.3 Generic Header Checks. I think I am doing roughly the same thing:
AC_CHECK_HEADERS([foo.h])
AC_CHECK_HEADERS([bar.h], [], [],
[#ifdef HAVE_FOO_H
# include <foo.h>
# endif
])
How do I use an AC_CHECK_HEADER header in an AC_COMPILE_IFELSE program?
Here is my test driver:
$ cat test.cxx
#include <immintrin.h>
#ifdef HAVE_X86INTRIN_H
# include <x86intrin.h>
#endif
int main(int argc, char** argv) {
unsigned int x;
return _rdseed32_step(&x);
}
$ g++ -mrdseed test.cxx -o test.exe
test.cxx: In function ‘int main(int, char**)’:
test.cxx:7:12: error: ‘_rdseed32_step’ was not declared in this scope
return _rdseed32_step(&x);
^~~~~~~~~~~~~~
test.cxx:7:12: note: suggested alternative: ‘_rdrand32_step’
return _rdseed32_step(&x);
^~~~~~~~~~~~~~
_rdrand32_step
$ g++ -DHAVE_X86INTRIN_H -mrdseed test.cxx -o test.exe
$ ./test.exe
$
Here is the distro and compiler:
$ lsb_release -a
LSB Version: :core-4.1-amd64:core-4.1-noarch
Distributor ID: Fedora
Description: Fedora release 28 (Twenty Eight)
Release: 28
$ g++ --version
g++ (GCC) 8.1.1 20180712 (Red Hat 8.1.1-5)
Here are the relevant parts from config.log:
configure:17624: checking if g++ supports -mrdseed
configure:17631: g++ -o conftest -mrdseed conftest.cpp >&5
conftest.cpp: In function 'int main(int, char**)':
conftest.cpp:38:17: error: '_rdseed32_step' was not declared in this scope
return _rdseed32_step(&x);
^~~~~~~~~~~~~~
conftest.cpp:38:17: note: suggested alternative: '_rdrand32_step'
return _rdseed32_step(&x);
^~~~~~~~~~~~~~
_rdrand32_step
configure:17631: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "Crypto++"
| ...
| #define STDC_HEADERS 1
| #define HAVE_SYS_TYPES_H 1
| #define HAVE_SYS_STAT_H 1
| #define HAVE_STDLIB_H 1
| #define HAVE_STRING_H 1
| #define HAVE_MEMORY_H 1
| #define HAVE_STRINGS_H 1
| #define HAVE_INTTYPES_H 1
| #define HAVE_STDINT_H 1
| #define HAVE_UNISTD_H 1
| #define HAVE_DLFCN_H 1
| #define LT_OBJDIR ".libs/"
| ...
| /* end confdefs.h. */
| #include <immintrin.h>
| #ifdef HAVE_X86INTRIN_H
| # include <x86intrin.h>
| #endif
| int main(int argc, char** argv) {
| unsigned int x;
| return _rdseed32_step(&x);
| }
configure:17645: result: no
You have tripped over an Autoconf gotcha. The docs for AC_CHECK_HEADER say:
If the system header file header-file is compilable, execute shell
commands action-if-found, otherwise execute action-if-not-found.
If you just want to define a symbol if the header file is available,
consider using AC_CHECK_HEADERS instead.
(Emphasis added)
Contrast that with the docs for AC_CHECK_HEADERS:
For each given system header file header-file in the blank-separated
argument list that exists, define HAVE_*header-file* (in all capitals).
If action-if-found is given, [...]
Note that unlike those for AC_CHECK_HEADERS, the docs for AC_CHECK_HEADER do not claim that any symbol will be defined if the header is found. In that case, the only thing done other than to report the result of the check is to run the commands in action-if-found. You can certainly put an AC_DEFINE in there to define a symbol, but you don't get that for free the way you do from AC_CHECK_HEADERS. If you want that, you can use AC_CHECK_HEADERS even for a single header.
I'm sure original the reason for the difference revolves around the fact that AC_CHECK_HEADERS checks possibly many headers. Additionally, sometimes you don't care about defining a symbol, or perhaps you expressly want to avoid doing so; for those cases you can use AC_CHECK_HEADER.
Here's a complete Autoconf input file that demonstrates a working variation on your check:
AC_PREREQ([2.69])
AC_INIT([test], [0.0.0])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
# Ensure that tests are run with the C++ compiler
AC_LANG([C++])
# Checks for header files.
AC_CHECK_HEADERS([x86intrin.h])
# Check support for -mrdseed
AS_IF([test "$ac_cv_header_x86intrin_h" = "yes"], [
CXXFLAGS_save=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -mrdseed"
XXX_PROGRAM="
#include <immintrin.h>
#ifdef HAVE_X86INTRIN_H
#include <x86intrin.h>
#endif
int main(void) {
unsigned int x;
return _rdseed32_step(&x);
}
"
AC_MSG_CHECKING([whether $CXX supports -mrdseed])
AC_COMPILE_IFELSE(
[AC_LANG_SOURCE([$XXX_PROGRAM])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
CXXFLAGS=$CXXFLAGS_save
])
AC_OUTPUT
Let assume that I can not have a private typedef in my header file. So I need to do connection to type that is specified from the outside. In other words the type MY_INT should be determined by the interface.
So are these two approaches equal?
First approach:
In file.h
#define MY_INT int
In file.c
typedef MY_INT my_int;
my_int *a,b;
Second approach
In file.c
typedef int my_int;
my_int *a,b;
Do both declare two variables: a pointer to an int and an integer variable?
Do both declare two variables: a pointer to an int and an integer variable?
Short: yes.
Long:
Macro substitution is nothing else then plain text substitution. So when you #define MY_INT int, everything the preprocessor does when he finds a MY_INT is replacing it with int.
After the preprocessor processed file.c in your first approach it will look exactly the same as file.c in the second approach.
You can have a look at the preprocessors output with most compilers. E.g. for GCC the command would look like this gcc -E -o file.i file.c. file.i will then contain the preprocessors output so the actual file wich will be passed to the compiler.
This is what GCC produced for your first approach:
# 1 "file1.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "file1.c"
# 1 "file.h" 1
# 2 "file1.c" 2
typedef int my_int;
my_int *a, b;
and here is the second one
# 1 "file2.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "file2.c"
# 1 "file.h" 1
# 2 "file2.c" 2
typedef int my_int;
my_int *a, b;
The only thing that differes is the name of the files I used. The rest is exactly the same.
I have the following really simple header file:
#ifndef __ZYNQ_CSORT_H__
#define __ZYNQ_CSORT_H__
#define CONSTANT 5
#endif
I am including this header file in another C file in the same folder. The preprocessor doesn't complain at all about the header file include, but when I try to print the value of the constant, it tells me that it is not defined. Anybody know what's up?
When I'm uncertain about what the preprocessor is up to, I find it is often revealing to run the C preprocessor by itself. For example, given test1.h:
#ifndef TEST1_H
#define TEST1_H
/* In TEST1_H */
#define CONSTANT 5
#endif
... and test1.c:
#include "test1.h"
#include "test1.h"
int main(int argc, char **argv) {
return CONSTANT;
}
... running cpp -C test1.c test1.c.out (the -C argument makes the preprocessor retain comments) gives test1.c.out as follows:
# 1 "test1.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test1.c"
# 1 "test1.h" 1
/* In TEST1_H */
# 2 "test1.c" 2
int main(int argc, char **argv) {
return 5;
}
Thus, for my case I can be confident that the right header file is being included.
CONSTANT would be undefined if __ZYNC_CSORT_H were already defined when this file was parsed.
Example =
#define a 100
#define b 200
main()
{
int c=a+b;
}
After preprocessing
Output-
#define a 100
main()
{
int c=a+200;
}
You could try refactoring the macros to allow external configuration, i.e.
/* config.h */
/* set defaults for a and b */
#ifndef a
#define a 100
#endif
#ifndef b
#define b 200
#endif
and
/* main.c */
#include "config.h"
int main(void)
{
int c = a + b;
}
Then you can set the macros externally when building, for instance like this:
$ gcc -E -Da=a main.c
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "config.h" 1
# 4 "main.c" 2
int main(void)
{
int c = a + 200;
}
$ gcc -E -Db=b main.c
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "config.h" 1
# 4 "main.c" 2
int main(void)
{
int c = 100 + b;
}
Now, of course you don't have to use a separate configuration header, but I'd recommend it from a maintenance perspective, it will make it easier to keep track of available configuration settings and their defaults.
#define a 100
#define b 200
main()
{
#undef b
int c=a+b;
}
No. What's your real goal?
If you want to do, it's better to make some script to do that.
If you don't want to preprocess a macro, just don't use it:
#define a 100
//#define b 200
int main()
{
int c = a + 200;
return 0;
}
The purpose of preprocessing is to process the preprocessing directives. I don't know of any way to keep a specific preprocessing directive, especially because the next step, compilation, doesn't know anything about these.
This is another reason why you should be careful when using macros -- when the name is found in the source, then it is substituted, no matter what:
#define a 100
main()
{
int a; // Compilation error happens here
....
}
Regarding Peter Miehle's answer, unifdef can be used to partially process #if and #ifdef directives, but it cannot be used to selectively expand macros. See http://dotat.at/prog/unifdef