matt
matt

Reputation: 243

char* to char[]

I have char* which is of fixed (known) width but is not null terminated.

I want to pass it into LOG4CPLUS_ERROR("Bad string " << char_pointer); but as its not null terminated it will print it all.

Any suggestions of some light weight way of getting "(char[length])*char_pointer" without performing a copy?

Upvotes: 6

Views: 872

Answers (7)

Ferruccio
Ferruccio

Reputation: 100658

I keep a string reference class in my toolkit just for these type of situations. Here is a greatly abbreviated version of that class. I trimmed away anything that is not relevant to this particular problem:

#include <iostream>

class stringref {
public:
    stringref(const char* ptr, unsigned len) : ptr(ptr), len(len) {}

    unsigned length() { return len; }
    const char* data() { return ptr; }

private:
    const char* ptr;
    unsigned len;
};

std::ostream& operator<< (std::ostream& os, stringref sr) {
    const char* data = sr.data();
    for (unsigned len = sr.length(); len--; )
        os << *data++;
    return os;
}

using namespace std;

int main (int argc, const char * argv[])
{
    cout << "string: " << stringref("test", 4) << endl;
}

or, in your case:

LOG4CPLUS_ERROR("Bad string " << stringref(char_pointer, length));

should work.

The idea of a string reference class is to keep enough information about a string (a size and a pointer) to refer to any block of memory which represents a string. It relies on you to make sure that the underlying string data is valid throughout the lifetime of a stringref object. This way you can pass around and process string information with a minimum of overhead.

Upvotes: 1

Ken Bloom
Ken Bloom

Reputation: 58770

Real iostreams

When you're writing to a real iostream, then you can just use ostream.write() which takes a char* and a size for how many bytes to write -- no null termination necessary. (In fact, any null characters in the string would be written to the ostream, and would not be used to determine the size.)

Logging libraries

In some logging libraries, the stream that you write to is not a real iostream. This is the case in Log4CPP.

However, in Log4CPlus which is what it appears matt is using, the object that you're writing to is a std::basic_ostringstream<tchar> (see loggingmacros.h and streams.h for the definition, since none of this is obvious from the documentation). There's just one problem: in the macro LOG4CPLUS_ERROR, the first << is already built into the macro, so he won't be able to call LOG4CPLUS_ERROR(.write(char_pointer,length)) or anything like that. Unfortunately, I don't see an easy way around this without deconstructing the LOG4CPLUS_ERROR error macro and getting into the internals of Log4CPlus

Solution

I'm not sure why you're trying to avoid copying the string at this point, since you can see that there's a lot of copying going on inside the logging library. Any attempt to avoid that extra string copy is probably unwarranted optimization.

I'm going to assume that it's an issue of code cleanliness, and maybe an issue of making sure the copy happens inside the LOG4CPLUS_ERROR macro, as opposed to outside it. In that case, just use:

LOG4CPLUS_ERROR("Bad string " << std::string(char_pointer, length));

Upvotes: 2

Nim
Nim

Reputation: 33655

We're getting hung up on the semantics of conversion between char* and char[]. Take a step back, what are you trying to do? If this is a simple case of on an error condition, streaming out the content of a structure to a stream, why not do it properly?

e.g.

struct foo
{
  char a1[10];
  char a2[10];
  char a3[10];
  char a4[10];
};

// free function to stream the above structure properly..
std::ostream operator<<(std::ostream& str, foo const& st)
{
  str << "foo::a1[";
  std::copy(st.a1, st.a1 + sizeof(st.a1), std::ostream_iterator<char>(str));
  str << "]\n";

  str << "foo::a2[";
  std::copy(st.a2, st.a2 + sizeof(st.a2), std::ostream_iterator<char>(str));
  str << "]\n";

  :

  return str;
}

Now you can simply stream out an instance of foo and don't have to worry about null terminated string etc.!

Upvotes: 2

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385174

No, you'll have to copy it. There is no proper conversion in the language that you can use to get the array type out of it.

It seems very odd that you want to do this, or that you have a non-terminated C-style string in the first place.

Why are you not using std::string?

Upvotes: 0

Georg Sch&#246;lly
Georg Sch&#246;lly

Reputation: 126105

If your goal is to print such a string, you could:

  1. Store the last byte.
  2. Replace it with \0.
  3. Print the string.
  4. Print the stored byte.
  5. Put the stored byte back into the last position of the string.

Wrap all this in a function.

Upvotes: 5

Chris
Chris

Reputation: 2060

When you know it is of fixed length: Why not simply add one more charakter to the size of the array? Then you can easily fill this last char with \0 terminating character and all will be fine

Upvotes: 0

sharptooth
sharptooth

Reputation: 170499

No, you'll have to deep-copy and null-terminate it. That code expects a null-terminated string and it means a contiguous block of characters ending with a null terminator.

Upvotes: 7

Related Questions