Determine programatically C from C++ as well as various versions

determine_c_or_cpp

Determine programatically C from C++ as well as various versions

  • In C the comma operator forces an array-to-pointer conversion while in C++ the result of the comma operator is the same value type as the RHS:

    int f() {
     char arr[100];
     return sizeof(0, arr); // returns 8 in C and 100 in C++
    }

    I used this example in a #CppPolls

  • C uses struct, union and enum tags as a primitive form of namespace see reference. So the following code will give sizeof int for C and sizeof struct T for C++

    #include <stdio.h> 
    
    extern int T; 
    
    int size(void) { 
        struct T { int i; int j; }; 
        return sizeof(T); 
    } 
    
    int main() { 
        printf( "%d\n", size() );     // sizeof(int) in C and sizeof(struct T) in C++
        
        return 0 ;
    }
  • Character literals are treated different in C and C++. An integer character constant has type int in C and a character lterals with a single char has type char. So the following code will likely produce 4 for C and 1 for C++

    #include<stdio.h>
    int main()
    {
       printf("%zu",sizeof('a'));    // sizeof(int) in C and sizeof(char) in C++
       return 0;
    }
  • C90 does not have // style comments, we can differentiate C90 from C99, C11 and C++:

    #include <stdio.h>
    
    int main() {
       int i = 2 //**/2
        ;
        printf( "%d\n", i ) ;    // 1 in C90
                                 // 2 in C99, C11 and C++
        return 0 ;
    }
  • C99 if statement implicitly defines a block scope above and below it (h/t this tweet:

     #include <stdio.h>
    
     struct s { long long m; };
    
     int main(void) {
       int x = 0;
       if (x)
         x = sizeof(struct s { char c;});
       else  
         printf("%zu\n", sizeof (struct s));   // 1 in C89
                                               // 8 in C99, assuming LP64
       return 0;
     }
  • K&R C used the unsigned preserving approach to integer promotions, which means when we mix unsigned and signed integers they are promoted to unsigned. Where as ANSI C and C++ use value preserving approach, which means when mixing signed and unsigned integers the are promoted to int if int can represent all values.

    #include <stdio.h>
    
    int main() {
       if( (unsigned char)1 > -1 ) {    // false for K&R C
                                        // true for ANSI C and C++
           printf("yes\n" ) ;  
       } 
    }
    
  • In C++ true and false are treated differently during preprocessing then the rest of the keywords and are not replaced with 0 and subepxressions of type bool are subject to integral promotions. In C true and false are not keywords but are macros with values 1 and 0 respetively if stdbool.h is included:

    #if true
    #define ISC 0
    #else
    #define ISC 1
    #endif
  • The Stackoverflow question Can C++ code be valid in both C++03 and C++11 but do different things? contains several examples of code that generate different results for C++03 and C++11:

    • New kinds of string literals [...] Specifically, macros named R, u8, u8R, u, uR, U, UR, or LR will not be expanded when adjacent to a string literal but will be interpreted as part of the string literal. The following code will print abcdef in C++03 and def in C++11:

      #include <cstdio>
      
      #define u8 "abc"
      
      int main()
      {
         const char *s = u8"def";
      
         printf( "%s\n", s ) ;     // abcdef in C++03 and def in C++11
         return 0;
      }
    • Using >> to close multiple templates is no longer ill-formed but can lead to code with different results in C++03 and C+11.

      #include <iostream>
      template<int I> struct X {
        static int const c = 2;
      };
      template<> struct X<0> {
        typedef int c;
      };
      template<typename T> struct Y {
        static int const c = 3;
      };
      static int const c = 4;
      int main() {
        std::cout << (Y
             <
             1> >::c >::c>::c) << 
             '\n';  
             // 0 in C++03 
                                                      
             // 0 in C++11
        std::cout << (Y
             
              < 
              1>>::c >::c>::c) << 
              '\n';  
              // 3 in C++03
                                                      
              // 0 in C++11
      }
             
            
  • We can identify if we are C++17 and greater by attempting to use trigrpahs, which were removed in C++17:

    int iscpp17orGreater(){
      //??/
      return 1; // trigraph on previous line will be ignored in C++17
      return 0; // trigraphs two lines above will form continuation and comment out the previous line
    }
  • How to tell C++20 from previous versions of C++. In C++20 introduced the spaceship operator <=> ( 🛸 ) and part of this change was rewritten candidates for equality and others see [over.match.oper]p3.4. The following code will print 0 in C++20 and 1 in previous versions of C++:

    #include <iostream>
    
    struct A {
     operator int() {return 1;}
    };
    bool operator==(A, int){return 0;}
    
    What is the result of:
    
    int main() {
       std::cout <<(1 == A{})<<"\n"; // 0 in C++20
                                     // 1 in previous versions of C++
    }
    
  • C++14 added the single quote as a digit seperator this means that prior to C++14 a comma in single quotes would be treated as a seperator in macros but C++14 onwards would not. Assuming we can indentify C++03, C++17 and C++20 we can use the following method to then differentiate C++11 and C++14.

    #define M(x, ...) __VA_ARGS__
    int x[2] = { M(1'2,3'4, 5) };
    // macro CPP03 is 1 is we are C++03
    // macro CPP17 is 1 if we are C++17
    // macro CPP20 is 1 is we are C++20
    int CPP14 = x[0] == 34 && !CPP17 && !CPP20;
    int CPP11 = x[0] == 5 && !CPP03 ;
  • We can combine this together into one program to detect both C and C++ and their respective versions. Note: K&R C did not have const so this needs some modifying to be portable for that case:

-1) == 0); const int comment = 2 //**/2 ; const int C90 = (comment == 1? 1 : 0) && ISC; const int C11 = ISC && (sizeof(u8"def") == 4); const int C99 = !C11 && !C90 && ISC; #if ISC int CPP03 = 0; int CPP11 = 0; int CPP14 = 0; int CPP17 = 0; int CPP20 = 0; #else template struct X { static int const c = 2; }; template<> struct X<0> { typedef int c; }; template struct Y { static int const c = 3; }; static int const c = 4; int CPP03 = (Y < 1>>::c >::c>::c == 3); struct A { operator int() {return 1;} }; bool operator==(A, int){return 0;} int iscpp17(){ //??/ return 1; // trigraph on previous line will be ignored in C++17 return 0; // trigraphs two lines above will form continuation and comment out the previous line } int isCPP20() {return !(1 == A());} int CPP20 = isCPP20(); int CPP17 = iscpp17() && !CPP20; #define M(x, ...) __VA_ARGS__ int x[2] = { M(1'2,3'4, 5) }; int CPP14 = x[0] == 34 && !CPP17 && !CPP20; int CPP11 = x[0] == 5 && !CPP03 ; #endif int main() { printf( "%s\n", (ISC ? "C" : "C++")); printf( "%s\n", (CPP03 ? "C++03" : "not C++03")); printf( "%s\n", (CPP11 ? "C++11" : "not C++11")); printf( "%s\n", (CPP14 ? "C++14" : "not C++14")); printf( "%s\n", (CPP17 ? "C++17" : "not C++17")); printf( "%s\n", (CPP20 ? "C++20" : "not C++20")); printf( "%s\n", (C90 ? "C90" : "not c90")); printf( "%s\n", (C99 ? "C99" : "not c99")); printf( "%s\n", (C11 ? "C11" : "not c11")); printf( "%s\n", (KandRC ? "K&R C" : "not K&R C")); return 0; }">
#if true
#define ISC 0
#else
#define ISC 1
#endif

#include <stdio.h>

#define u8 "abc"

const int KandRC = (((unsigned char)1 > -1) == 0);
const int comment = 2 //**/2
    ;
const int C90 = (comment == 1? 1 : 0) && ISC;
const int C11 = 
    ISC && (sizeof(u8"def") == 4);
const int C99 = !C11 && !C90 && ISC;

#if ISC
int CPP03 = 0;
int CPP11 = 0;
int CPP14 = 0;
int CPP17 = 0;
int CPP20 = 0;
#else
template<int I> struct X {
  static int const c = 2;
};
template<> struct X<0> {
  typedef int c;
};
template<typename T> struct Y {
  static int const c = 3;
};
static int const c = 4;
int CPP03 = (Y
      < 
      1>>::c >::c>::c == 
      3);


      struct 
      A {
 
      operator 
      int() {
      return 
      1;}
};

      bool 
      operator==(A, 
      int){
      return 
      0;}


      int 
      iscpp17(){
    
      //??/
    
      return 
      1; 
      // trigraph on previous line will be ignored in C++17
    
      return 
      0; 
      // trigraphs two lines above will form continuation and comment out the previous line
}


      int 
      isCPP20() {
      return !(
      1 == 
      A());}


      int CPP20 = isCPP20();

      int CPP17 = iscpp17() && !CPP20;

#
      define 
      M(x, ...) __VA_ARGS__

      int x[
      2] = { 
      M(
      1'2,
      3'4, 
      5) };

      int CPP14 = x[
      0] == 
      34 && !CPP17 && !CPP20;

      int CPP11 = x[
      0] == 
      5 && !CPP03 ;
#
      endif



      int 
      main()
{
   
      printf( 
      "%s\n", (ISC ? 
      "C" : 
      "C++"));
   
      printf( 
      "%s\n", (CPP03 ? 
      "C++03" : 
      "not C++03"));
   
      printf( 
      "%s\n", (CPP11 ? 
      "C++11" : 
      "not C++11"));
   
      printf( 
      "%s\n", (CPP14 ? 
      "C++14" : 
      "not C++14"));
   
      printf( 
      "%s\n", (CPP17 ? 
      "C++17" : 
      "not C++17"));
   
      printf( 
      "%s\n", (CPP20 ? 
      "C++20" : 
      "not C++20"));
   
      printf( 
      "%s\n", (C90 ? 
      "C90" : 
      "not c90"));
   
      printf( 
      "%s\n", (C99 ? 
      "C99" : 
      "not c99"));
   
      printf( 
      "%s\n", (C11 ? 
      "C11" : 
      "not c11"));
   
      printf( 
      "%s\n", (KandRC ? 
      "K&R C" : 
      "not K&R C"));

   
      return 
      0;
}
     
Owner
Shafik Yaghmour
Interests: C++, C, compilers and undefined behavior. Stackoverflow contributor in C++, C tags. Also find me on Twitter: https://twitter.com/shafikyaghmour
Shafik Yaghmour
Similar Resources

Determine if the WebClient Service (WebDAV) is running on a remote system

GetWebDAVStatus Small project to determine if the Web Client service (WebDAV) is running on a remote system by checking for the presence of the DAV RP

Nov 28, 2022

CMake macro to determine the language of a header file

CMake Determine Header Language CMake macro to determine the language of a header file. Status Travis CI (Ubuntu) AppVeyor (Windows) Coverage Biicode

Dec 7, 2018

Einsums in C++ Provides compile-time contraction pattern analysis to determine optimal operation to perform

Einsums in C++  Provides compile-time contraction pattern analysis to determine optimal operation to perform

Einsums in C++ Provides compile-time contraction pattern analysis to determine optimal operation to perform. Examples This will optimize at compile-ti

Dec 15, 2022

UClamp backports and custom tunings for different kernel versions/devices

Linux kernel ============ This file was moved to Documentation/admin-guide/README.rst Please notice that there are several guides for kernel develop

Jan 14, 2022

Advanced keylogger written in C++ , works on all windows versions use it at your own risk !

Advanced keylogger written in C++ , works on all windows versions use it at your own risk !

About Keylogger Keyloggers or keystroke loggers are software programs or hardware devices that track the activities (keys pressed) of a keyboard. Key

Dec 26, 2022

Servo library with stm developed by the Liek Software Team. We are working on new versions.

Liek-Servo-Library Liek Servo Library is a library that makes it easy for you to drive servo motors with STM32F10x series cards. The library is still

Nov 4, 2022

A LKM rootkit targeting 4.x and 5.x kernel versions which opens a backdoor that can be used to spawn a reverse shell to a remote host and more.

A LKM rootkit targeting 4.x and 5.x kernel versions which opens a backdoor that can be used to spawn a reverse shell to a remote host and more.

Umbra Umbra (/ˈʌmbrə/) is an experimental LKM rootkit for kernels 4.x and 5.x (up to 5.7) which opens a network backdoor that spawns reverse shells to

Dec 10, 2022

Techniques based on named pipes for pool overflow exploitation targeting the most recent (and oldest) Windows versions

Table of Contents Table of Contents Introduction Named-Pipes Introduction Exploitation Spraying the non-paged pool Memory Disclosure/Arbitrary Read Co

Dec 16, 2022

Tools to measure libcurl performance delta between versions

relative Tools to measure libcurl performance delta between versions build-many This script iterates over all the curl versions listed in the top of t

Aug 30, 2021

Patch for Sierra's PowerChess to run on newer Windows Versions 9x

What is it? I recently stumbled upon the following thread: https://sourceforge.net/p/dxwnd/discussion/general/thread/98dd46dfc6/?page=0 Some people we

Mar 27, 2022

Orca - Advanced Malware with multifeatures written in ASM/C/C++ , work on all windows versions ! (some features still under developing and not stable)

Orca - Advanced Malware with multifeatures written in ASM/C/C++ , work on all windows versions  !  (some features still under developing and not stable)

About Orca Orca is an Advanced Malware with multifeatures written in ASM/C/C++ features Run in Background (Hidden Mode) Records keystrokes and saves t

Dec 26, 2022

Cppbackport - A backport of C++11/14/17 features to earlier versions

This is a backport of the current C++ standard library to C++03/11/14. Obviously not everything can be backported, but quite a bit can. Quick Start Th

Sep 5, 2021

This repo contains demo exploits for CVE-2022-0185. There are two versions here.

CVE-2022-0185 This repo contains demo exploits for CVE-2022-0185. There are two versions here. The non-kctf version (fuse version) specifically target

Dec 24, 2022

⚔️ A tool for cross compiling shaders. Convert between GLSL, HLSL, Metal Shader Language, or older versions of GLSL.

⚔️ A tool for cross compiling shaders. Convert between GLSL, HLSL, Metal Shader Language, or older versions of GLSL.

A cross compiler for shader languages. Convert between SPIR-V, GLSL / GLSL ES, HLSL, Metal Shader Language, or older versions of a given language. Cross Shader wraps glslang and SPIRV-Cross, exposing a simpler interface to transpile shaders.

Dec 30, 2022

An easy-to-learn, high performance network io library written in modern cpp (c++11), It borrows concepts from Netty, and with well defined internal modules, It enables you to write rpc, http/https,websocket application with just few lines。

A new beginning of network programming What is Netplus Netplus is a network programming library written in c++11. It's highly extensible, and with def

Dec 15, 2022

An ATTiny85 implementation of the well known sleep aid. Includes circuit, software and 3d printed case design

An ATTiny85 implementation of the well known sleep aid. Includes circuit, software and 3d printed case design

dodowDIY An ATTiny85 implementation of the well known sleep aid. Includes circuit, software and 3d printed case design The STL shells are desiged arou

Sep 4, 2022

C++ implementations of well-known (and some rare) algorithms, while following good software development practices

ProAlgos: C++ This project is focused on implementing algorithms and data structures in C++, while following good software engineering practices, such

Dec 7, 2022
Well I'd like to test myself how good I am before making something massive :">

Pratice-Cpp Well I'd like to test myself how good I am before making something massive :"> Before I upload something special, that I'll release in my

May 6, 2022
About Write a program to create a circular doubly linked list and perform insertions and deletions of various cases

Write a program to create a circular doubly linked list and perform insertions and deletions of various cases Circular Doubly Linked List Circular Dou

Aug 28, 2021
This is a simple UNITEST to test the implementation of the the various container types of the C++ standard template library

ft_container UNITest. This is a simple UNITEST to test the implementation of the the various container types of the C++ standard template library that

Dec 27, 2022
A place where you can learn and practise various Problems and algorithms
A place where you can learn and practise various Problems and algorithms

Problem-Solving Problem solving is an art of solving some real time challenges. And this is a place to get started, you can find many problems to solv

Apr 22, 2022
Programming-Basics - This Repository Contains source codes of various programming languages. Please Contribute to make this Useful.
Programming-Basics - This Repository Contains source codes of various programming languages. Please Contribute to make this Useful.

Programming-Basics About ❓ Want To Start your Open-Source Journey Without Facing Difficulties?,If Yes, Then You Are at The Right Place! ?? Don't Know

Dec 8, 2022
Nov 29, 2021
`lv_lib_100ask` is a reference for various out of the box schemes based on lvgl library or an enhanced interface for various components of lvgl library.

Introduction lv_lib_100ask is a reference for various out of the box schemes based on lvgl library or an enhanced interface for various components of

Dec 15, 2022
The Pizza Compass will determine your location and direct you to the nearest pizza place. It’s like a regular compass, but better!

Pizza_Compass A Particle project named Pizza_Compass Welcome to your project! Every new Particle project is composed of 3 important elements that you'

Aug 16, 2022
Calculator to determine unrealized gains or losses in % and $ form.

Personal-Project-G-L-Calculator in C++ Ryan Ramirez - [email protected] - UNLV Student Calculator to calculate unrealized gains or losses in % a

Oct 19, 2021
Determine date based on days spent

date-based-on-days-spent Determine date based on days spent. Enter the number of days since the beginning of Gregorian calendar to get the date of tha

Dec 6, 2021