Showing posts with label CPP. Show all posts
Showing posts with label CPP. Show all posts

Thursday, December 28, 2023

Narrowing type conversions in C/C++

 Hi, my friends and just everyone! :)

You shouldn't think that I forgot about my blog. After more then 6 years I decided to continue writing articles. And I'm glad to present my new article about strange behavior of C++ compilers. However, the reason maybe more interesting. E.g. in C++ standards.

So today I would like to talk about implicit type conversions and particular about implicit narrowing conversion of types.

Me and my friends were sure that if we can lose data the compiler has to show error or at least show warning.
Actually, look at this:

1
2
3
4
5
6
7
8
#include <cstdint>

void f(uint16_t) {}

int main() {
    uint32_t x = 0xFFFFFFFF;
    f(x);
}

I think you are sure that gcc or clang compilers have to show warning or error? :) But no!
$ rm -f a.out; g++ main1.cpp && ./a.out
$ rm -f a.out; clang++ main1.cpp && ./a.out
$
As we can see there are no any warnings or errors. Hmmm. Ok! Maybe we can use special warnings level? No problem!
$ rm -f a.out; g++ -Wall -Wextra -Wpedantic main1.cpp && ./a.out
$ rm -f a.out; clang++ -Wall -Wextra -Wpedantic main1.cpp && ./a.out
$
So, we don't see any warnings or errors. And any warnings flags couldn't help. In that case we can write the program which can demonstrate big problems with that behavior.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <cstdint>

void Bob(uint16_t x) {
    std::cout << "I'm Bob. My salary is $"
              << x
              << std::endl;
}

struct Snob {
    Snob(uint16_t x) {
        std::cout << "I'm Snob and my salary is $"
                  << x
                  << std::endl;
    }
};

int main() {
    uint32_t x = 0xFFFF0001; // 4294901761

    std::cout << "I'm the boss and I would like to give money to Bob and Snob. "
              << "Guys! Take your salary! "
              << "It is $"
              << x
              << std::endl;
    
    Bob(x);

    Snob snob(x);
}

The result (gcc):
$ rm -f a.out; g++ -std=c++17 -Wall -Wextra -Wpedantic main2.cpp && ./a.out
I'm the boss and I would like to give money to Bob and Snob. Guys! Take your salary!
It is $4294901761
I'm Bob. My salary is $1
I'm Snob and my salary is $1
$
The result (clang):
$ rm -f a.out; clang++ -std=c++17 -Wall -Wextra -Wpedantic main2.cpp && ./a.out
I'm the boss and I would like to give money to Bob and Snob. Guys! Take your salary!
It is $4294901761
I'm Bob. My salary is $1
I'm Snob and my salary is $1
$

OK? Do you understand what problems can be? Currently, I have no idea about reasons. I have not found the explanation of this behavior yet. So if you know I would be happy if you could explain to me.

Have a nice time! :)
Best regards,
Vasiliy V. Bodrov aka Bodro,
the 28-th of December, 2023.

Tuesday, May 16, 2017

How do you swap two variable?

Hi!

How do you swap two variable?

Look at this! It's a C++ code.
#include <iostream>

using namespace std;

inline void swap_var(int& _x, int& _y) {
    int _ = _x; _x = _y; _y = _;
}

inline void swap_xor(int& _x, int& _y) {
    _x ^= _y; _y ^= _x; _x ^= _y;
}

inline void swap_math(int& _x, int& _y) {
    _x += _y; _y = _x - _y; _x -= _y;
}

int main(void) {
    int a = 5;
    int b = 77201;

    cout << a << ":" << b << endl;
    swap_var(a, b);
    cout << a << ":" << b << endl;
    swap_xor(a, b);
    cout << a << ":" << b << endl;
    swap_math(a, b);
    cout << a << ":" << b << endl;
}


It's the result:
$ rm -f t; g++ -Wall -Wextra -Werror -O2 t.cpp -o t; ./t;
5:77201
77201:5
5:77201
77201:5
$


This is a C code.
#include <stdlib.h>
#include <stdio.h>

void swap_var(int* _x, int* _y) {
    int _ = *_x; *_x = *_y; *_y = _;
}

void swap_xor(int* _x, int* _y) {
    *_x ^= *_y; *_y ^= *_x; *_x ^= *_y;
}

void swap_math(int* _x, int* _y) {
    *_x += *_y; *_y = *_x - *_y; *_x -= *_y;
}

int main(void) {
    int a = 5;
    int b = 77201;

    (void) printf("%d:%d\n", a, b);
    swap_var(&a, &b);
    (void) printf("%d:%d\n", a, b);
    swap_xor(&a, &b);
    (void) printf("%d:%d\n", a, b);
    swap_math(&a, &b);
    (void) printf("%d:%d\n", a, b);

    return EXIT_SUCCESS;
}


It's the result:
$ rm -f t; gcc -Wall -Wextra -Werror -O2 t.c -o t; ./t
5:77201
77201:5
5:77201
77201:5
$

And finally, Erlang :)
-module(t).
-export([t/0]).

swap({X, Y}) ->
    {Y, X}.

t() ->
    A = {1, 2},
    swap(A).

It's the result:
$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> c(t).
{ok,t}
2> t:t().
{2,1}
3> q().
ok
4> $

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 16, 2017.

Thursday, May 11, 2017

How to create a final class in C ++? Do you know?

Hi, my dear hackers!

We continue to talk about C++.
I assume you know the Java programming language. And also I assume you know keyword final. But do you think we can use it in C++? I mean the standard of the 98-th year (ISO/IEC 14882:1998). It turns out you can!

Look at this!


I'm trying to compile and run this code. I use GNU compiler and GNU/Linux as the operation system. I know and like them!

$ g++ -Wall -Wextra -Werror -o final final.cpp
$ ./final 
cons Lock
cons A
$ g++ -Wall -Wextra -Werror -o final final.cpp -DI_WANT_ERROR
final.cpp: In constructor 'B::B()':
final.cpp:13:2: error: 'Lock::Lock()' is private
  Lock() { cout << "cons Lock" << endl; }
  ^
final.cpp:26:6: error: within this context
  B() { cout << "cons B" << endl; }
      ^
$

You can see that we have an error when we use macro I_WANT_ERROR. Why?

The constructor of the class Lock cant't be called by the child classes. However class A is a friend of class Lock. So we can create an instance of class A because the constructor of class A can call the constructor of class Lock. Do you agree with me? I continue. But if we don't use a virtual inheritance we can create an instance of class B, because the constructor of class B can call the constructor of class A and the constructor of class A can call the constructor of class Lock. It's confusing and difficult, isn't it? But if you understand everything is simple.

Look at this: B -> A -> Lock.
It's OK? Do you understand me?

But if we use the virtual inheritance the constructor of class B must call the constructor of class Lock directly! But it can't do it because it doesn't have access to it (I mean the constructor of class Lock) because the constructor of class Lock is private and class B isn't a friend of class Lock. It's a very simple, my dear friend! And it's great!

This reaction as the final keywords applied to the class, isn't it? Do you agree with me? :)


Best regards,
Vasiliy V. Bodrov aka Bodro,
the 10-11-th of May, 2017 year.

Sunday, May 7, 2017

"A pure virtual method is called." Do you know how to do this in C++?

Hello, my dear friend!

"A pure virtual method is called". Do you know how to do this in C++?
 I'll show you this. I like GNU compiler, so I will use it.

Example #1. Simple.

Code:

#include <cstdlib>
#include <iostream>

class A {
public:
 A() {
  init();
 }

 void init(void) {
  f();
 }

 virtual void f(void) = 0;
};

class B : public A {
public:
 virtual void f(void) {
  std::cout << "f() in B" << std::endl;
 }
};

int main(void) {
 B b;
 b.f();
 
 return EXIT_SUCCESS;
}

Build and result:

bodro@bodronote:~/workspace/develop/test/pure_virtual_func$ export LC_ALL=C
bodro@bodronote:~/workspace/develop/test/pure_virtual_func$ ls -lah t1.cpp 
-rw-r--r-- 1 bodro bodro 297 May  7 13:24 t1.cpp
bodro@bodronote:~/workspace/develop/test/pure_virtual_func$ g++ -Wall -Wextra \
> -Werror -O0 -o t1.bin t1.cpp && ./t1.bin
pure virtual method called
terminate called without an active exception
Aborted
bodro@bodronote:~/workspace/develop/test/pure_virtual_func$

Example #2. I will use an assembler (AT&T).

Code:

#include <cstdlib>
#include <iostream>

class A {
public:
 A() {
  asm ("mov (%rax),%rcx");
  asm ("mov 0(%rcx),%rcx");
  asm ("call *%rcx");
 }

 virtual void f(void) = 0;
};

class B : public A {
public:
 virtual void f(void) {
  std::cout << "f() in B" << std::endl;
 }
};

int main(void) {
 B b;
 b.f();

 return EXIT_SUCCESS;
}

Build and result:

bodro@bodronote:~/workspace/develop/test/pure_virtual_func$ export LC_ALL=C
bodro@bodronote:~/workspace/develop/test/pure_virtual_func$ ls -lah t2.cpp 
-rw-r--r-- 1 bodro bodro 333 May  7 13:36 t2.cpp
bodro@bodronote:~/workspace/develop/test/pure_virtual_func$ g++ -Wall -Wextra \
> -Werror -O0 -o t2.bin t2.cpp && ./t1.bin 
pure virtual method called
terminate called without an active exception
Aborted
bodro@bodronote:~/workspace/develop/test/pure_virtual_func$

The story of how it works I'll write later.


Best regards,
Vasiliy V. Bodrov aka Bodro,
the 7-th of May, 2017 year.

How to reverse singly linked list in C (trivial way)

There is a beautiful morning. It's snowing. And I decided to write one more article. Today it will be just simple article where I would...