Why doesn’t this redacted code work the same as the original?

Asked

Viewed 66 times

1

I’ve been studying C++ for a while and I want to train by rewriting functions already done by me in C# only in C++.

I wrote a simple code that computes a IV of a Hash, very simple even, calling the same methods using the same argument in both methods the returns are different and did not understand why.

CalcIV(byte[] data) in C#:

    public static byte CalcIV(byte[] pass) {
        int iv = 0;
        foreach(byte k in pass) {
            iv += k;
            iv *= k + 1;
        }
        return (byte)(iv / pass.Length);
    }

calc_iv(byte buffer[]) in C++:

#include <iostream>

typedef unsigned char byte;

byte calc_iv(byte buffer[])
{
    int iv = 0;
    size_t len = sizeof(buffer); // get buffer size
    for(int i = 0; i < len; i++) {
        byte I = buffer[i];
        iv += I;
        iv *= I + 1;
    }
    return iv / (len);
}

And what is returned is the following:

// Em C#
byte[] data = new byte[] {41, 32, 16};
return CalcIV(data);
// Resultado é 152

// Em C++
byte buf[] = {41, 32, 16};
byte iv = calc_iv(buf);
return iv;
// Resultado é 50

Both results should be equal, but I don’t understand why in C# the same code gives 152 and in C++ gives 50.

Somebody explain to me?

  • put to work in ideone: https://ideone.com/ and I would start testing by operators += and *= I don’t know how they behave in C++

1 answer

4


and in C++ gives 50.

Not really, because the program has an undetermined behavior so it can give any value as a result, something that can confirm here

The problem is here:

size_t len = sizeof(buffer); // get buffer size

Since an array in C is a pointer to the first element, this sizeof only get the size of the pointer buffer, which will normally be 4 bytes. In that situation the for executes 4 times and accesses an element outside the array, thus picking up a random value in memory.

It can solve this problem in some ways:

  1. Passing the size also as parameter:

    This is a common solution in pure C, where functions that use arrays always receive their size. An exception would be a string because the end can be determined by '\0'.

    byte calc_iv(byte buffer[], size_t len)
    {
        int iv = 0;
        for(int i = 0; i < len; i++) {
           byte I = buffer[i];
           iv += I;
           iv *= I + 1;
       }
       return iv / (len);
    }
    

    And calling on the main thus:

    byte iv = calc_iv(buf, sizeof(buf)/sizeof(buf[0]));
    

    In main the compiler can determine the total size of the allocated vector because a static allocation is made, so sizeof(buf) will give the total size of the array in bytes, which when divided by the size of the first element in bytes, results in the amount of array elements.

    The same can no longer be done inside the function because there is no way to know how the array was built, and the array has no associated size information. It is merely a pointer to the first element.

    See this code running on Ideone

  2. Passing just one vector

    This scenario is the most similar to C# because the vector has size information internally, so it is not necessary to send any more information:

    #include <iostream>
    #include <vector>
    
    typedef unsigned char byte;
    
    byte calc_iv(std::vector<byte> buffer)
    {
        int iv = 0;
        for(int i = 0; i < buffer.size(); i++) {
            byte I = buffer[i];
            iv += I;
            iv *= I + 1;
        }
        return iv / buffer.size();
    }
    
    
    int main(){
        std::vector<byte> buf = {41, 32, 16};
        byte iv = calc_iv(buf);
        std::cout<<(int)iv<<std::endl;
    
       return 0;
    }
    

    See this example also in Ideone

    In this case it was necessary to add the #include <vector> at the top, and the len was exchanged directly by buffer.size().

    In order to instantiate the vector in the main the way I did it has to compile with C++11 or higher.

  • I can replace the size line with a size_t len = sizeof(buffer) / sizeof(buf[0]); instead of passing as a parameter?

  • @Cypherpotato If you are speaking within the function it will not work, because within the function sizeof(buffer) is really just the size of the pointer. No main works, because that’s where the array was created.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.