-Wundef does not warn about an undefined symbol in front of #ifdef - c++

Please consider the following code:
// program.cpp
#include <iostream>
int main() {
#ifdef LINUX
std::cout << "Linux\n";
#elif MAC
std::cout << "Mac\n";
#elif WINDOWS
std::cout << "Windows\n";
#elif BSD
std::cout << "BSD\n";
#else
std::cout << "Something else\n";
#endif
return 0;
}
If I compile it with both clang and gcc,
clang++ -Wundef -DBSD -o program program.cpp
# or
g++ -Wundef -DBSD -o program program.cpp
I will get warnings for not defining symbols MAC and WINDOWS, but no warning for the symbol LINUX:
program.cpp:6:7: warning: 'MAC' is not defined, evaluates to 0 [-Wundef]
#elif MAC
^
program.cpp:8:7: warning: 'WINDOWS' is not defined, evaluates to 0 [-Wundef]
#elif WINDOWS
^
2 warnings generated.
According to the gcc man page:
-Wundef
Warn if an undefined identifier is evaluated in an "#if" directive.
Such identifiers are replaced with zero.
It says in an #if directive. Is it because the LINUX is not inside that structure?
If that's the case, how can I tell compiler to emit warnings for the undefined symbol LINUX?
clang version 12.0.1
gcc (GCC) 11.1.0
Target: x86_64-pc-linux-gnu (artixlinux)

The reason is that your preprocessor code asks if LINUX is defined. But for MAC, WINDOWS and BSD you don’t bother checking whether the symbol is defined; instead, your code assumes it is defined and asks for its value.
Change your code to use #elif defined(…) instead of #elif … to fix the warning.

Related

Got undeclared identifier error for a function argument (C++) in Linux, but not in Windows

I have written these codes:
#include <iostream>
#include <limits>
#include <string>
#ifdef _WIN32
#include "WinSock2.h"
#include "WS2tcpip.h"
#pragma comment(lib,"ws2_32.lib")
#elif __linux__
#include <sys/socket.h>
#include <arpa/inet.h>
#define SOCKET socket
#else
#error Compiler cannot interpret platform. Please compile this program in Windows 32/64-bit or Linux!
#endif
//...some codes here for initalization for _WIN32
int socket_create(SOCKET &socketHandler)
{
socketHandler = socket(AF_INET, SOCK_STREAM, 0);
if (socketHandler == INVALID_SOCKET)
{
#ifdef _WIN32
return (WSAGetLastError());
#else
return -1;
#endif
}
else
{
return 0;
}
}
//...some codes for other functions
//...main function
When compiled using Clang 11.0.0 on Windows 10 x64 with arguments:
clang server.cpp -Wall -Wextra -std=c++17 -g -glldb -lws2_32 -fexceptions -O0 -o target\debug\win-amd64\server.exe -fms-compatibility -m64
it was flawless. The program compiled without even a warning and was running perfectly.
However, bringing it straight to linux (Ubuntu 20.04 x64, with clang-11 and libc++-dev & libc++abi-dev installed), and compiled using Clang 11.0.0 in there with arguments:
clang-11 server.cpp -Wall -Wextra -std=c++17 -g -glldb -fexceptions -O0 -o target\debug\deb-amd64\server.exe -m64
It gives me this error:
error: use of undeclared identifier 'socketHandler'
int socket_create(SOCKET &socketHandler)
^
and
error: expected ';' after top level declarator
int socket_create(SOCKET &socketHandler)
^
Question: Why is it different in Linux? Did I miss something in declaration? If so, how could the same version of clang in Windows would compile it fine, while straight up refused in Linux?
TBH, this is my first time compiling things in Linux, so I don't know if I miss something that I should do in Linux but not in Windows for C++. Thank you.
What socket() in Linux returns is int, not socket nor SOCKET.
You are using #define SOCKET socket in Linux mode and it will have it put function name where type name is expected like this:
int hoge(){ return 0; }
int fuga(hoge& x) { // error
return 0;
}
This error is not produced in Windows because the problematic line #define SOCKET socket is not used in Windows thanks to the #ifdef directives.
In conclusion, the line #define SOCKET socket should be typedef int SOCKET;.

error : to_string was not declared in this scope

I am compiling the code on solaris 5.11.
G++ version is 4.8.2.
The same code works on Ubuntu but gives the error: 'to_string() was not declared in this scope' on solaris.
I went through many links and tried the following things:
Adding 'std::' before to_string(). This gives error - 'to_string is not a member of std'
Added 'std=c++11' or 'std=c++0x' while compilation.
Both the above things do not work.
Is there anything related to Solaris?
The actual code was very huge. So simulating the error in sample code below.
temp.cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str;
int i = 10;
str = "john age is " + to_string(i);
cout << str;
return 0;
}
command: g++ temp.cpp -std=c++0x -o temp
For GCC 4.8.2 the to_string functions are defined conditionally, according to the following:
#if ((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
&& !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
The GLIBCXX_USE_C99 macro depends on a large number of C99 functions being supported by the OS, so presumably the necessary C99 library functions were not found when building GCC on Solaris. So the to_string definitions are absent.
In current versions of GCC the condition is more fine-grained, and checks whether the C99 functions are defined in C++98 mode and C++11, so that the absence of any C99 function doesn't disable everything:
#if __cplusplus >= 201103L
//...
#if _GLIBCXX_USE_C99_STDIO
It's not possible to backport these improvements to GCC 4.8, so you might need to update to at least GCC 6.
compile using std=c++11 as below
g++ -std=c++11 filename.cc
Note : your compiler must support c++11

__extern_inline func results in undefined reference error

When I compile this c++ code with g++ 4.8.5 with -O0 -std=c++11,
#include <stdio.h>
__extern_inline float func(float x) { return x*x; }
int main(int argc, char *argv[])
{
printf("%d\n", func(100));
}
I get this link error
/tmp/ccMiVRIL.o: In function `main':
test.cpp:(.text+0x18): undefined reference to `func(float)'
collect2: error: ld returned 1 exit status
however, if I add -O1 or -O2 to the compiler option, it builds successfully.
Also if I change "__extern_inline" to "extern __inline" or "__extern_always_inline", it also builds. I see similar behavior with clang.
I want to have that code (keep __extern_inline, since the definition lives in a third-party lib and I don't want to touch) to be able to link even under -O0. What can I do? Is there any compiler option or #defines to work this error around?
I've read this document, but it doesn't seem to help for my case
https://clang.llvm.org/compatibility.html#inline
Also it looks like __extern_inline is defined as follows in sys/cdefs.h
#define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
I think it's because following macro in features.h:
/* Decide whether we can define 'extern inline' functions in headers. */
#if __GNUC_PREREQ (2, 7) && defined __OPTIMIZE__ \
&& !defined __OPTIMIZE_SIZE__ && !defined __NO_INLINE__ \
&& defined __extern_inline
# define __USE_EXTERN_INLINES 1
#endif
As you can see, extern inlines are explicitly allowed only for optimized builds.

-Wundef is not being ignored with pragma in g++

Given the following code:
#if MACRO_WITHOUT_A_VALUE
int var;
#endif
int main(){}
When compiled with, g++ -std=c++1z -Wundef -o main main.cpp,
it produces the following warning:
main.cpp:1:5: warning: "MACRO_WITHOUT_A_VALUE" is not defined [-Wundef]
#if MACRO_WITHOUT_A_VALUE
^
I'd like to keep the warning flag enabled, but suppress this particular instance.
I apply the following:
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wundef"
#pragma GCC diagnostic push
#endif
#if MACRO_WITHOUT_A_VALUE
int var;
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
int main(){}
This only solves the problem in clang++.
The command clang++ -std=c++1z -Wundef -o main main.cpp builds without warnings.
The command g++ -std=c++1z -Wundef -o main main.cpp builds with the same [-Wundef] warning as before.
How can I suppress -Wundef warnings in g++?
g++ (Ubuntu 5.1.0-0ubuntu11~14.04.1) 5.1.0
clang version 3.8.0
What I've done before when third party headers were inducing warnings was to wrap them in my own private header that uses #pragma GCC system_header to just silence all the warnings from that header. I use my own wrapper to keep the includes neat and allow for an additional customization point in the future if needed.
This isn't disabling the warning, but fixing the preprocessor code to avoid it.
The below tests are based on a similar issue here, using clang -Weverything...
#define ZERO 0
#define ONE 1
#define EMPTY
// warning: 'NOTDEFINED' is not defined, evaluates to 0 [-Wundef]
#if NOTDEFINED
#warning NOTDEFINED
#endif
// false
#if ZERO
#warning ZERO
#endif
// true
#if ONE
#warning ONE
#endif
// error: expected value in expression
#if EMPTY
#warning EMPTY
#endif
// false
#if defined(NOTDEFINED) && NOTDEFINED
#warning NOTDEFINED
#endif
// false
#if defined(ZERO) && ZERO
#warning ZERO
#endif
// true
#if defined(ONE) && ONE
#warning ONE
#endif
// error: expected value in expression
#if defined(EMPTY) && EMPTY
#warning EMPTY
#endif
The one liner #if defined(SOME_MACRO) && SOME_MACRO can avoid this warning. To explicitly handle the case...
#if defined(DEBUG_PRINT)
#if DEBUG_PRINT
... true
#else
... false
#endif
#else
#error DEBUG_PRINT must be defined
#endif
To handle EMPTY see this: How to test if preprocessor symbol is #define'd but has no value?

Easylogging 8.91 not compling without c++11

I want to use the library without C++11 but it won't compile for me:
(Theoretically it should as per documentation #http://easylogging.muflihun.com:
"For lower version of C++ (non-C++11), please consider using Easylogging++ v8.91. ")
error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
File structure:
./Main.cpp
./logger/easylogging++.h
Contents of Main.cpp:
#include "logger/easylogging++.h"
_INITIALIZE_EASYLOGGINGPP
using namespace std;
int main(int argc, char* argv[]) {
LINFO << "This is my first log";
return 0;
}
../src/logger/easylogging++.h: In function ‘std::string easyloggingpp::internal::threading::getCurrentThreadId()’:
../src/logger/easylogging++.h:691:16: error: ‘std::this_thread’ has not been declared
ss << std::this_thread::get_id();
Compiler: gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1), OS: Ubuntu 14.04 LTS
As T.C. suggested in the solution is to change this section of code at the top of easylogging++.h:
#if defined(__GNUC__)
# define _ELPP_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
# define _ELPP_CXX0X 1
# elif (_ELPP_GCC_VERSION >= 40801)
# define _ELPP_CXX11 1
# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
#endif // defined(__GNUC__)
Changing both _ELPP_CXX0X and _ELPP_CXX11 to 0 will fix the issue.