Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ with extern "C" in namespace prefix resolution and optimization level dependency

Tags:

c++

c

linux

I have a file "test.cxx" with

namespace net {
    extern "C" {
#include <arpa/inet.h>
    }
}

int main() {
    htons(1024);
}

When compiling with -O1 or more everything's fine.

When compiling with -O0:

error: ‘htons’ was not declared in this scope
suggested alternative: ‘net::htons’

Then I change htons to net::htons.

When compiling with -O0 everything's fine.

When compiling with -O1 or more:

error: expected unqualified-id before ‘(’ token

Reproduced that on gcc-4.9.2 and clang-3.7.0. Can someone explain why does it happen?

like image 936
rayslava Avatar asked Mar 05 '15 07:03

rayslava


1 Answers

It happens because at -O0, call is compiled to htons function and your declaration for this function is inside namespace net. In optimized version, -O2 for example, call is replaced with a macro.

You can verify this by pre-compiling your program using gcc -O0 -E v/s gcc -O2 -E

When htons is used
At -O2, htons is translated to

int main() {
    (__extension__ (
       {
          register unsigned short int __v, __x = (unsigned short int) (1024);
          if (__builtin_constant_p (__x))
             __v = ((unsigned short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff) << 8)));
          else
             __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc");       
          __v;
      }
    ));
}

Making the code not throw the resolution error.

error: ‘htons’ was not declared in this scope

When net::htons is used

When you replace ntohs with net::ntohs, ntohs define is used / exposed for optimization and your pre-processed code look as:

int main() {
  net::(__extension__ ({... /* removed for Brevity */ ...}));
}

And hence the error

error: expected unqualified-id before ‘(’ token

Why does it happen
htons may be implemented as a function or a macro. If it is defined as macro, htons would work fine. But if it is defined as a function net::htons would work fine.

It appears at -O1 or higher, header files expose macro versions instead of function.

Possible solutions

using namespace net;  // Not recommended
#ifndef htons  // Recommended
using net::htnos;
#endif
extern "C" { // Add all declarations in global space
#include <arpa/inet.h>
}
like image 69
Mohit Jain Avatar answered Oct 19 '22 03:10

Mohit Jain