37

I'm working in a C++ unmanaged project.

I need to know how can I take a string like this "some data to encrypt" and get a byte[] array which I'm gonna use as the source for Encrypt.

In C# I do

  for (int i = 0; i < text.Length; i++)
    buffer[i] = (byte)text[i];

What I need to know is how to do the same but using unmanaged C++.

Thanks!

Chris Young
  • 15,627
  • 7
  • 36
  • 42
Vic
  • 2,878
  • 4
  • 36
  • 55

9 Answers9

50

If you just need read-only access, then c_str() will do it:

char const *c = myString.c_str();

If you need read/write access, then you can copy the string into a vector. vectors manage dynamic memory for you. You don't have to mess with allocation/deallocation then:

std::vector<char> bytes(myString.begin(), myString.end());
bytes.push_back('\0');
char *c = &bytes[0];
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    If he wants a byte array does he need the terminating '\0'? In which case you can use data() for read only. – Martin York Feb 02 '09 at 22:37
  • i wasn't sure whether he needs the \0 or not. If he doesn't he now knows that he can use .data() . thanks for commenting on that, Martin. – Johannes Schaub - litb Feb 02 '09 at 22:48
  • 1
    This answer seems correct and may work but assuming the data store for a vector of char is contiguous and won't change is dangerous. – Mark Feb 03 '09 at 19:10
  • 4
    Assuming it's contiguous is not at all dangerous, it's a guarantee of vector (first paragraph under std::vector in the C++ spec IIRC). Assuming it won't change is safe provided that certain specified functions aren't called - amounting to those which might provoke a resize(). – Steve Jessop Feb 03 '09 at 19:55
  • Mark, it is very safe to "assume" that, because it's always the case that the vector is contiguous :) and it's also safe to assume the pointer is valid. you don't modify the vector so that it has to reallocate its buffer. so the vector's first element address remains the same of course. – Johannes Schaub - litb Feb 03 '09 at 22:39
  • The `bytes-.push_back('\0')` is incorrect for the task at hand, getting the bytes. It would be correct in order to create a zero-terminated string. – Cheers and hth. - Alf Oct 07 '16 at 20:47
  • @Cheersandhth.-Alf correct. Depending on what he wants, he can use either, either omitting the push_back or doing it. "getting a char[] array" sounds like he wants it null terminated, so I wanted to be sure he knows how to null terminate it. – Johannes Schaub - litb Oct 07 '16 at 20:52
25

std::string::data would seem to be sufficient and most efficient. If you want to have non-const memory to manipulate (strange for encryption) you can copy the data to a buffer using memcpy:

unsigned char buffer[mystring.length()];
memcpy(buffer, mystring.data(), mystring.length());

STL fanboys would encourage you to use std::copy instead:

std::copy(mystring.begin(), mystring.end(), buffer);

but there really isn't much of an upside to this. If you need null termination use std::string::c_str() and the various string duplication techniques others have provided, but I'd generally avoid that and just query for the length. Particularly with cryptography you just know somebody is going to try to break it by shoving nulls in to it, and using std::string::data() discourages you from lazily making assumptions about the underlying bits in the string.

Christopher Smith
  • 5,372
  • 1
  • 34
  • 18
  • Can you please shed light on how using string::data() is better than using string::begin() ? One returns a pointer to the underlying storage, the other returns an iterator, how does that help security? – nirvanaswap Jun 25 '19 at 00:26
  • 1
    Variable length arrays, like `unsigned char buffer[mystring.length()]` are not standard C++. Some compilers support them, but Visual Studio does not. – 273K Dec 30 '21 at 01:33
4

Normally, encryption functions take

encrypt(const void *ptr, size_t bufferSize);

as arguments. You can pass c_str and length directly:

encrypt(strng.c_str(), strng.length());

This way, extra space is allocated or wasted.

  • If you are passing a pointer and a length then you should be using data() rather than c_str() to indicate it is not being used as a string. – Martin York Feb 02 '09 at 22:38
3

In C++17 and later you can use std::byte to represent actual byte data. I would recommend something like this:

std::vector<std::byte> to_bytes(std::string const& s)
{
    std::vector<std::byte> bytes;
    bytes.reserve(std::size(s));
      
    std::transform(std::begin(s), std::end(s), std::back_inserter(bytes), [](char c){
        return std::byte(c);
    });

    return bytes;
}
Galik
  • 47,303
  • 4
  • 80
  • 117
1

From a std::string you can use the c_ptr() method if you want to get at the char_t buffer pointer.

It looks like you just want copy the characters of the string into a new buffer. I would simply use the std::string::copy function:

length = str.copy( buffer, str.size() );
Nick Haddad
  • 8,767
  • 3
  • 34
  • 38
  • Some implementations of std::string may use reference counting, so a copy would not necessarily result in new bytes that would be safe to write over. – Larry Gritz Feb 02 '09 at 22:00
1

If you just need to read the data.

encrypt(str.data(),str.size());

If you need a read/write copy of the data put it into a vector. (Don;t dynamically allocate space that's the job of vector).

std::vector<byte>  source(str.begin(),str.end());
encrypt(&source[0],source.size());

Of course we are all assuming that byte is a char!!!

Martin York
  • 257,169
  • 86
  • 333
  • 562
0

If this is just plain vanilla C, then:

strcpy(buffer, text.c_str());

Assuming that buffer is allocated and large enough to hold the contents of 'text', which is the assumption in your original code.

If encrypt() takes a 'const char *' then you can use

encrypt(text.c_str())

and you do not need to copy the string.

Mark
  • 6,108
  • 3
  • 34
  • 49
0

You might go with range-based for loop, which would look like this:

std::vector<std::byte> getByteArray(const string& str)
{
    std::vector<std::byte> buffer;
    for (char str_char : str)
        buffer.push_back(std::byte(str_char));

    return buffer;
}
-7

I dont think you want to use the c# code you have there. They provide System.Text.Encoding.ASCII(also UTF-*)

string str = "some text;
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);

your problems stem from ignoring the encoding in c# not your c++ code

Hippiehunter
  • 967
  • 5
  • 11