in a function, that gets unsigned char && unsigned char length,
void pcap_callback(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet)
{
std::vector<unsigned char> vec(packet, packet+pkthdr->len); // optimized from foo.
std::stringstream scp;
for (int i=0;i<pkthdr->len;i++) {
scp<<vec[i];
}
std::string mystr = std::string(scp.rdbuf()->str());
std::cout << "WAS: " << packet << std::endl;
std::cout << "GOOD: " << scp.str() << std::endl;
std::cout << "BAD: " << scp.str().c_str() << std::endl;
std::cout << "TEST: " << mystr.size() << std::endl;
assert(mystr.size() == pkthdr->len);
}
Results:
WAS: prints nothing (guess there is a pointer to const.. case)
GOOD: prints data
BAD: prints nothing
TEST, assert: prints that mystr.size() is equal to passed unsigned char size.
I tried:
string.assign(scp.rdbuf());
memcpy(char, scp.str(), 10);
different methods of creating/allocating temporary chars, strings
No help.. it is wanted to get a std::cout'able std::string that contains data, (which was picked from foo, which was unsigned char, which was packet data).
Guessing either the original foo may not be null-terminated, or the problem is something like this - simple, but can't get in.. what are the things to look for here?
(this code is another attempt to use libpcap, just to print packets in C++ way, without using known C++ magic wrappers like libpcapp).
For a quick test, throw in a check for scp.str().size() == strlen(scp.str().c_str()) to see if there are embedded '\0' characters in the string, which is what I suspect is happening.
I think you're going about this the wrong way. It looks like you're dealing with binary data here, in which case you can't expect to meaningfully output it to the screen as text. What you really need is a hex dump.
const unsigned char* ucopy = packet;
std::ios_base::fmtflags old_flags = std::cout.flags();
std::cout.setf(std::ios::hex, std::ios::basefield);
for (const unsigned char* p = ucopy, *e = p + pkthdr->len; p != e; ++p) {
std::cout << std::setw(2) << std::setfill('0') << static_cast<unsigned>(*p) << " ";
}
std::cout.flags(old_flags);
This will output the data byte-by-byte, and let you examine the individual hex values of the binary data. A null byte will simply be output as 00.
Check std::cout.good() after the failed output attempt. My guess is that there's some failure on output (i.e. trying to write a nonprintable character to the console), which is setting failbit on cout.
Also check to ensure the string does not start with a NULL, which would cause empty output to be the expected behavior :)
(Side note, please use reinterpret_cast for unsigned char *ucopy = (unsigned char*)packet; if you're in C++ ;) )
Related
Why is the change of my local variable's value getting reflected into original variable? I am passing it by value in C++.
#include <string>
#include <iostream>
void test(std::string a)
{
char *buff = (char *)a.c_str();
buff[2] = 'x';
std::cout << "In function: " << a;
}
int main()
{
std::string s = "Hello World";
std::cout << "Before : "<< s << "\n" ;
test(s);
std::cout << "\n" << "After : " << s << std::endl;
return 0;
}
Output:
Before : Hello World
In function: Hexlo World
After : Hexlo World
As soon as you wrote
buff[2] = 'x';
and compiled your code all bets were off. Per [string.accessors]
const charT* c_str() const noexcept;
Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
Complexity: constant time.
Requires: The program shall not alter any of the values stored in the character array.
emphasis mine
Since you are not allowed to modify the characters that the pointer points to but you do, you have undefined behavior. The compiler at this point is allowed to do pretty much whatever it wants. Trying to figure out why it did what it did is meaningless as any other compiler might not do this.
The moral of the story is do not cast const away unless you are really sure that you know what you are doing and if you do you need to, then document the code to show you know what you are doing.
Your std::string implementation uses reference counting and makes a deep copy only if you modify the string via its operator[] (or some other method). Casting the const char* return value of c_str() to char* will lead to undefined behavior.
I believe since C++11 std::string must not do reference counting anymore, so switching to C++11 might be enough to make your code work (Edit: I did not actually check that before, and it seems my assumption was wrong).
To be on the safe side, consider looking for a string implementation that guarantees deep copying (or implement one yourself).
#include <cstring>
#include <string>
#include <iostream>
void test(std::string a)
{
// modification trough valid std::string API
a[2] = 'x';
const char *buff = a.c_str(); // only const char* is available from API
std::cout << "In function: " << a << " | Trough pointer: " << buff;
// extraction to writeable char[] buffer
char writeableBuff[100];
// unsafe, possible attack trough buffer overflow, don't use in real code
strcpy(writeableBuff, a.c_str());
writeableBuff[3] = 'y';
std::cout << "\n" << "In writeable buffer: " << writeableBuff;
}
int main()
{
std::string s = "Hello World";
std::cout << "Before : "<< s << "\n" ;
test(s);
std::cout << "\n" << "After : " << s << std::endl;
return 0;
}
Output:
Before : Hello World
In function: Hexlo World | Trough pointer: Hexlo World
In writeable buffer: Hexyo World
After : Hello World
I have the below code.
main()
{
test::RouteMessage *Rtmesg = new test::RouteMessage;
test::RouteV4Prefix *prefix = new test::RouteV4Prefix;
test::RouteMessage testRtmesg;
prefix->set_family(test::RouteV4Prefix::RT_AFI_V4);
prefix->set_prefix_len(24);
prefix->set_prefix(1000);
Rtmesg->set_routetype(test::RouteMessage::RT_TYPE_BGP);
Rtmesg->set_allocated_v4prefix(prefix);
Rtmesg->set_flags(test::RouteMessage::RT_FLGS_NONE);
Rtmesg->set_routeevnt(test::RouteMessage::BGP_EVNT_V4_RT_ADD);
Rtmesg->set_nexthop(100);
Rtmesg->set_ifindex(200); Rtmesg->set_metric(99);
Rtmesg->set_pref(1);
int size = Rtmesg->ByteSize();
char const *rt_msg = (char *)malloc(size);
google::protobuf::io::ArrayOutputStream oarr(rt_msg, size);
google::protobuf::io::CodedOutputStream output (&oarr)
Rtmesg->SerializeToCodedStream(&output);
// Below code is just to see if everything is fine.
google::protobuf::io::ArrayInputtStream iarr(rt_msg, size);
google::protobuf::io::CodedInputStream Input (&iarr)
testRtmesg.ParseFromCodedStream(&Input);
Vpe::RouteV4Prefix test_v4Prefix = testRtmesg.v4prefix();
cout << std::endl;
std::cout << "Family " << test_v4Prefix.family() << std::endl;
std::cout << "Prefix " << test_v4Prefix.prefix()<< std::endl;
std::cout << "PrefixLen " << test_v4Prefix.prefix_len() << std::endl;
// All the above outputs are fine.
cout << std::endl;
cout << rt_msg; <<------------ This prints absolutely junk.
cout << std::endl;
amqp_bytes_t str2;
str2 = amqp_cstring_bytes(rt_msg); <<----- This just crashes.
printf("\n str2=%s %d", str2.bytes, str2.len);
}
Any operation on the above rt_msg just crashes. I want to use the above buffer to send to socket and another rabbitmq publish APIs.
Anybody out there who had similar issue...or worked out similar code ?
Protocol Buffers is a binary serialization format, not text. This means:
Yes, if you write the binary data to cout, it will look like junk (or crash).
The data is not NUL-terminated like C strings. Therefore, you cannot pass it into a function like amqp_cstring_bytes which expects a NUL-terminated char* -- it may cut the data short at the first 0 byte, or it may search for a 0 byte past the end of the buffer and crash. In general, any function that takes a char* but does not also take a length won't work.
I'm not familiar with amqp, but it looks like the function you are trying to call, amqp_cstring_bytes, just builds a amqp_bytes_t, which is defined as follows:
typedef struct amqp_bytes_t_ {
size_t len;
void *bytes;
} amqp_bytes_t;
So, all you have to do is something like:
amqp_bytes_t str2;
str2.bytes = rt_msg;
str2.len = size;
I am trying to use this example:
std::size_t s2 = boost::asio::buffer_size(buffer);
const void* p2 = boost::asio::buffer_cast<const void*>(buffer);
And I am getting a vaild size s2 and some seemingly valid address p2.
Now, how could I create a cout or printf loop or phrase a debug-statement, to see the content of p2?
I bet this is quite basic, but currently I can't see what I am missing.
Tried this:
std::cout << "TEST: " << boost::asio::buffer_cast<const void*>(buffer) << std::endl;
but it only prints out the address, not the content
and this:
for(int i =0; i!=s2; i++){
std::cout << "TEST: " << p2[i];
}
std::cout << std::endl;
but I am ending up with compile errors, like C0253 - unknown size.
So, how can I print out the content of p2?
You can print the bytes pointed to by buffer as:
std::size_t s2 = boost::asio::buffer_size(buffer);
const void* p2 = boost::asio::buffer_cast<const void*>(buffer);
unsigned char const* bytes = static_cast<unsigned char const*>(p2);
for(std::size_t i = 0 ; i < s2 ; ++i)
std::cout << static_cast<unsigned int>(bytes[i]);
Of course, you have to interpret the output.
You can print the hexadecimal values instead which is easier to interpret:
std::cout << std::hex << static_cast<unsigned int>(bytes[i]);
// ^^^^^^^^ note this
I think you have to #include<iomanip> for this.
The content of p2 is a memory address...since p2 is a pointer.
A void* means that the language + libraries are not aware of the type of data being referenced.
You can't print the value being pointed to if you don't know of what type it is.
Consider
#include <string>
#include <iostream>
int main()
{
/*
hello
5
hel
3
*/
char a[] = "hello";
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
a[3] = 0;
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
/*
hello
5
hel o
5
*/
std::string b = "hello";
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
b[3] = 0;
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
getchar();
}
I expect std::string will behave identical to char array a. That's it, insert null character in the middle of the string, will "terminate" the string. However, it is not the case. Is my expectation wrong?
A std::string is not like a usual C string, and can contain embedded NUL characters without problems. However, if you do this you will notice the string is prematurely terminated if you use the .c_str() function to return a const char *.
No - std::strings are not NUL-terminated like C "strings"; the std::string records its length independently.
#Lou is right: don't do that. Instead, do this:
b.erase (3, b.length());
Yes, your expectation is wrong. std::string is meant to be different from C strings (e.g. not necessarily stored in consecutive memory / an array).
To duplicate the first section's behavior, try std::cout << b.c_str() instead of std::cout << b.
I expect std::string will behave identical to char array a.
Why? Nothing in the documentation, anywhere, having to do with std::string says it does this.
My suggestion, stop treating like C++ as C plus some stuff.
I would like to compare a character literal with the first element of string, to check for comments in a file. Why use a char? I want to make this into a function, which accepts a character var for the comment. I don't want to allow a string because I want to limit it to a single character in length.
With that in mind I assumed the easy way to go would be to address the character and pass it to the std::string's compare function. However this is giving me unintended results.
My code is as follows:
#include <string>
#include <iostream>
int main ( int argc, char *argv[] )
{
std::string my_string = "bob";
char my_char1 = 'a';
char my_char2 = 'b';
std::cout << "STRING : " << my_string.substr(0,1) << std::endl
<< "CHAR : " << my_char1 << std::endl;
if (my_string.substr(0,1).compare(&my_char1)==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
std::cout << "STRING : " << my_string.substr(0,1) << std::endl
<< "CHAR : " << my_char2 << std::endl;
if (my_string.substr(0,1).compare(&my_char2)==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
std::cout << "STRING : " << my_string << std::endl
<< "STRING 2 : " << "bob" << std::endl;
if (my_string.compare("bob")==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
}
Gives me...
STRING : b
CHAR : a
NOPE...
STRING : b
CHAR : b
NOPE...
STRING : bob
STRING 2 : bob
WOW!
Why does the function think the sub-string and character aren't the same. What's the shortest way to properly compare chars and std::string vars?
(a short rant to avoid reclassification of my question.... feel free to skip)
When I say shortest I mean that out of a desire for coding eloquence. Please note, this is NOT a homework question. I am a chemical engineering Ph.D candidate and am coding as part of independent research. One of my last questions was reclassified as "homework" by user msw (who also made a snide remark) when I asked about efficiency, which I considered on the border of abuse. My code may or may not be reused by others, but I'm trying to make it easy to read and maintainable. I also have a bizarre desire to make my code as efficient as possible where possible. Hence the questions on efficiency and eloquence.
Doing this:
if (my_string.substr(0,1).compare(&my_char2)==0)
Won't work because you're "tricking" the string into thinking it's getting a pointer to a null-terminated C-string. This will have weird effects up to and including crashing your program. Instead, just use normal equality to compare the first character of the string with my_char:
if (my_string[0] == my_char)
// do stuff
Why not just use the indexing operator on your string? It will return a char type.
if (my_string[0] == my_char1)
You can use the operator[] of string to compare it to a single char
// string::operator[]
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str ("Test string");
int i; char c = 't';
for (i=0; i < str.length(); i++)
{
if (c == str[i]) {
std::cout << "Equal at position i = " << i << std::endl;
}
}
return 0;
}
The behaviour of the first two calls to compare is entirely dependent on what random memory contents follows the address of each char. You are calling basic_string::compare(const char*) and the param here is assumed to be a C-String (null-terminated), not a single char. The compare() call will compare your desired char, followed by everything in memory after that char up to the next 0x00 byte, with the std::string in hand.
Otoh the << operator does have a proper overload for char input so your output does not reflect what you are actually comparing here.
Convert the decls of and b to be const char[] a = "a"; and you will get what you want to happen.
Pretty standard, strings in c++ are null-terminated; characters are not. So by using the standard compare method you're really checking if "b\0" == 'b'.
I used this and got the desired output:
if (my_string.substr(0,1).compare( 0, 1, &my_char2, 1)==0 )
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
What this is saying is start at position 0 of the substring, use a length of 1, and compare it to my character reference with a length of 1. Reference