1

I would like to switch between different BYTE Arrays after user input. I need to apply the same processing to different arrays depending on user input, but I would like to avoid repeating the code. One solution could be to create one array ahead of the if logic and then copys the correct byte pattern into that array. I need the BYTE variable someData in my main function because a followup function needs it for data processing.

Currently I am getting this error : 'someData' was not declared in this scope' This is my code:

#include <iostream>
#include <string>
#include <Windows.h>

using namespace std;

int main()
{
    string titel;
    std::cout << "CHOOSE PARAM: ";
    std::cin >> titel;

    if (titel == "PARAM1") {
        BYTE someData[17] = { 0x00, 0x87, 0x80, 0x83, 0x10, 0x09, 0x08, 0x00, 0x83, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00 };
    }
    else if (titel == "PARAM2")
    {
        BYTE someData[16] = { 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xBE, 0x00, 0x40 };
    }
    else if (titel == "PARAM3")
    {
        BYTE someData[8] = { 0x01, 0x01, 0x16, 0xD5, 0x01, 0xD8, 0x00, 0x00 };
    }

    std::cout << "SomeData: ";

    for(int i = 0; i < 23; i++)
    {
        printf("%02x ", someData[i]);
    }
}

I would like to switch between different BYTE Arrays after user input.

9
  • 1
    Investigate how you could use : std::map<std::string,std::vector>. The reason to use std::vector is that it can be any length). And you processing function can accept a const reference to said std::vector. You should also not "#include <windows.h>" (C++ has <cstdint> + std::uint8_t for bytes). You should not be using using namespace std; and use std::print (C++23). Commented Aug 8 at 13:59
  • 1
    Question back, how are you trying to learn C++? Since you're already picking up some windows and "C" style coding it doesn't seem to be an up-to-date source. Commented Aug 8 at 14:01
  • 1
    for(int i = 0; i < 23; i++) would do out of bound access, even for the larger array anyway. Commented Aug 8 at 14:08
  • 1
    See also What's the problem with "using namespace std;"? and undefined behaviour. Commented Aug 8 at 14:13
  • 1
    @JesperJuhl That's also why using std::vector/std::array in combination with "range based" for loops is recommended. And also why I think OP is learning C++ from a "not so good" source. Commented Aug 8 at 15:48

2 Answers 2

7

I need the BYTE variable someData in my main function because a followup function needs it for data processing.

Your "because" clause is actually a reason why you do not need someData in your main function. You need someData in the follow-up function. The only trick here is that your data has different types. A template can help with that. Have the follow-up function accept a reference to an array as its parameter, and let the template parameter specify the size of this array.

#include <iostream>
#include <string>

using BYTE = unsigned char; // No need to depend on Windows.h

template <size_t size>
void do_work(const BYTE (&someData)[size]) {
    std::cout << "SomeData: ";

    for(size_t i = 0; i < size; i++) // Corrected limit, not 23
    {
        printf("%02x ", someData[i]);
    }
    printf("\n");
}

int main()
{
    std::string title;
    std::cout << "CHOOSE PARAM: ";
    // std::cin >> title;
    // Simulate user input:
    title = "PARAM2"; std::cout << "\n";

    if (title == "PARAM1") {
        do_work({ 0x00, 0x87, 0x80, 0x83, 0x10, 0x09, 0x08, 0x00, 0x83, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00 });
    }
    else if (title == "PARAM2")
    {
        do_work({ 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xBE, 0x00, 0x40 });
    }
    else if (title == "PARAM3")
    {
        do_work({ 0x01, 0x01, 0x16, 0xD5, 0x01, 0xD8, 0x00, 0x00 });
    }

}

As long as the follow-up function does not need to change the data, you can pass the brace-enclosed list directly to the function, no need to define a variable in main. There's also no need to write the size of each array, as the compiler will count that for you.


A caveat to the above is that even though the code for do_work is written once, it compiles three times, once for each size. If do_work is large, this might lead unnecessary bloat in your executable. You could get around this by delegating to a function that takes a pointer and a size, which as of a few years ago (C++20) can be in the form of a std::span.

// The real function
void do_work(std::span<const BYTE> someData) {
    std::cout << "SomeData: ";

    for(size_t i = 0; i < someData.size(); i++)
    {
        printf("%02x ", someData[i]);
    }
    printf("\n");

    // A range-based loop is also possible:
    std::cout << "          ";
    for(auto& data : someData)
    {
        printf("%02x ", data);
    }
    printf("\n");

    // A pointer to the data is available via the `data()` member.
    [[maybe_unused]] const BYTE* as_pointer = someData.data();
}

// The wrapper to forward const arrays to the real function.
template <size_t size>
void do_work(const BYTE (&someData)[size]) {
    do_work(std::span{someData});
}

The small delegating function template helps the compiler go from a braced-enclosed list to a std::span. If you stick to defining variables inside your if statement (presumably because you need non-constant data) then this delegation is not necessary.

Sign up to request clarification or add additional context in comments.

5 Comments

std::span avoid to have 2 related parameters.
@Jarod42 Thanks. I had thought I was overlooking something.
@JaMiT Thanks for your help and all the work. Unfortunately I am getting a compiler error: main.cpp|27|error: no matching function for call to 'do_work(<brace-enclosed initializer list>)'|
@Alex Do you have one of the functions whose parameter is const BYTE (&someData)[size]? I can see that error occurring if you have the do_work(std::span<const BYTE> someData) function without the do_work(const BYTE (&someData)[size]) overloads.
@Alex Since it was easy to mis-copy, I merged the code blocks.
0

As said, the someData must be declared outside the if-blocks:

#include <iostream>
#include <string>
#include <cstring>
#include <memory>
#include <Windows.h>

using namespace std;

int main()
{
    string titel;
    std::cout << "CHOOSE PARAM: ";
    std::cin >> titel;

    BYTE * someData = 0;
    int NsomeData =0 ;
    if (titel == "PARAM1") {
        BYTE tmp[17] = { 0x00, 0x87, 0x80, 0x83, 0x10, 0x09, 0x08, 0x00, 0x83, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00 };
        someData = new BYTE[17] ;
        memcpy(someData,tmp,sizeof(BYTE[17])) ;
        NsomeData = 17 ;
    }
    else if (titel == "PARAM2")
    {
        BYTE tmp[16] = { 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xBE, 0x00, 0x40 };
        someData = new BYTE[16] ;
        memcpy(someData,tmp,sizeof(BYTE[16])) ;
        NsomeData = 16 ;
    }
    else if (titel == "PARAM3")
    {
        BYTE tmp[8] = { 0x01, 0x01, 0x16, 0xD5, 0x01, 0xD8, 0x00, 0x00 };
        someData = new BYTE[8] ;
        memcpy(someData,tmp, sizeof(BYTE[8])) ;
        NsomeData = 8 ;
    }

    std::cout << "SomeData: ";
    for(int i = 0; i < NsomeData; i++)
        printf("%02x ", someData[i]);
   
    delete[] someData ;
}

6 Comments

Why not just a std::span<BYTE>? It can refer to the BYTE array constants (which are compiled into binary anyways) together with their respecitve size. It can be used like an array or std::vector. And no additional array allocation is necessary.
I was not trying to start a beauty contest here but to stay as close as possible to the OP's question
Something like that.
This is exactly what I was looking for. Thank you R. J. Mathar. But one more thing ;-) It seems after the memcpy command the size of somedata is wrong. It should be 17 but it is 8!? Please add this to the code: if (titel == "PARAM1") { BYTE tmp[17] = { 0x00, 0x87, 0x80, 0x83, 0x10, 0x09, 0x08, 0x00, 0x83, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00 }; ... std::cout << "Size of tmp: " << sizeof(tmp) << std::endl; std::cout << "Size of someData: " << sizeof(someData) << std::endl;
Output:CHOOSE PARAM: PARAM1 Size of someData: 8 Size of tmp: 20 Size of someData: 8 SomeData: 00 87 80 83 10 09 08 00
@Alex: This sizeof(....) computations you are using are the number of bytes in the pointers, not the numbers of bytes in the arrays.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.