How detect if file was overwrote?, - c++

In my C/C++ program I need to check if the file from what I read have been overwrote (its inode was changed or some new lines were added). If I'm now wrong fstat and fstat64 can be usefull only when I use Linux but not for windows. Is there any universal (to work for complex OSes) way to do this? And also can you tell me how do this using fstat64?

You can keep track of when the file was last written to know if it has been modified. The cross platform solution is using boost::filesystem. Windows doesn't have fstat64 AFAIK.
http://www.boost.org/doc/libs/1_44_0/libs/filesystem/v2/doc/index.htm
http://rosettacode.org/wiki/File_modification_time#C.2B.2B
#include <boost/filesystem/operations.hpp>
#include <ctime>
#include <iostream>
int main( int argc , char *argv[ ] ) {
if ( argc != 2 ) {
std::cerr << "Error! Syntax: moditime <filename>!\n" ;
return 1 ;
}
boost::filesystem::path p( argv[ 1 ] ) ;
if ( boost::filesystem::exists( p ) ) {
std::time_t t = boost::filesystem::last_write_time( p ) ;
std::cout << "On " << std::ctime( &t ) << " the file " << argv[ 1 ]
<< " was modified the last time!\n" ;
std::cout << "Setting the modification time to now:\n" ;
std::time_t n = std::time( 0 ) ;
boost::filesystem::last_write_time( p , n ) ;
t = boost::filesystem::last_write_time( p ) ;
std::cout << "Now the modification time is " << std::ctime( &t ) << std::endl ;
return 0 ;
} else {
std::cout << "Could not find file " << argv[ 1 ] << '\n' ;
return 2 ;
}
}

I don't have a code sample for you, but can you check the last modified time of the file, against what it was when you first opened it?
Edit
Found a pretty good snippet that appears to do the trick
http://www.jb.man.ac.uk/~slowe/cpp/lastmod.html

Related

Why had not CV been based on Semaphore when it was being implemented on Linux?

Recently, I need a method in my program to notify a thread in another. Of course, I want it goes faster and more stably. So I compared the condition_variable in the STL with the POSIX-Semaphore of the Linux. I'm using gcc-8.2.0 and its libs. The codes attached later.
the results is:
Avg delay of CV notification is :10.752us
StD is:3.911us
Max delay is:473us
Min delay is:5us
Avg delay of Semaphore notification is :10.307us
StD is:5.768us
Max delay is:537us
Min delay is:4us
The performance of both are similar, but I think at least Semaphore has 3 advantages as following:
No spurious waking.
No notification leaking.
No lock/mutex must be used.
My question is:
Why CV spuriously wakes up, eventhough a Semaphore never do so?
Why had not CV been based on Semaphore when it was being implemented on Linux?
Semaphores can not be used when CV was implemented on Linux?
About the second advantage of Semaphore:
We must call the wait/wait_for/wait_until of CV before the executing of notify_one/notify_all, or the notification would be lost, but it is hard to be ensured in real works.
Imaging a simplest scene with only one productor and only one consumer: When the productor is sending notification, the consumer might be listenning on, or might be processing the data comed with earlier notifications. This is a very very normal situation, but CV's method can not work with it smoothly.
Semaphore can work perferctly in this situation. Whenever you sem_post a notification, it always waits for you untill you call sem_wait. Just likes that "How many you put, is how many you can get".
I know the wait_for/wait_until func of CV can accept a timeout argument, that give us a chance to re-work after losing a notification instead of to keep waiting stupidly, but it is not yet an event-mechanism likes "notifying/responsing", rather likes a busy-checking loop, and will unnecessarily consume more cpu time. When running my test, I really observed a higher cpu usage of CV than that of Semaphore.
The experts who developed gcc are absolutely not fresh-men like me, so I want to know why they didn't use Semaphore.
Just because it easily results buggy programs?
Guns and cannons might result invasion and death, but they might also be good tools for peace and balance.
This is my testing program:
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <condition_variable>
#include <iomanip>
#include <iostream>
#include <memory>
#include <semaphore.h>
#include <thread>
using namespace std;
using namespace std::chrono;
using namespace std::chrono_literals;
class FakeLock {
public:
void lock() {};
void unlock() {};
};
int g_iLoops = 1024;
condition_variable g_cvsPing;
condition_variable_any g_cvaPing;
sem_t g_semPing, g_semPong;
steady_clock::time_point g_tpStart;
unique_ptr<uint64_t[]> g_upBuffer;
uint64_t* g_puiElaps;
atomic_int64_t g_aiPos = -1;
// thread body by means of CV
void thdCVS( int iMyId ) {
/* Although a real lock is not required in many cases, but condition-
* variable always needs one Arbitrarily. I think it's a small drawback,
* because I believe std::mutex::lock() is a costly operation, especially
* some time it must falls into busy checking.
*/
mutex mtxToken;
unique_lock<mutex> realLock( mtxToken );
int iLast, iPos;
iLast = iPos = g_aiPos;
while ( iPos < g_iLoops ) {
if ( ( iPos & 1 ) == iMyId ) {
// phase 1 : as a sender
// sleep a little while to ensure the peer has been listenning
this_thread::sleep_for( 1us );
g_tpStart = steady_clock::now();
asm volatile( "mfence":::"memory" );
g_aiPos.store( ( iLast = ++iPos ), memory_order_release );
g_cvsPing.notify_one();
} else {
// phase 0 : as a listenner
g_cvsPing.wait( realLock );
iPos = g_aiPos.load( memory_order_acquire );
asm volatile( "mfence":::"memory" );
/* calculate only when iPos has been changed, since we might be
* waked spuriously or the timeout be hitted.
*/
if ( iPos > iLast && iPos < g_iLoops )
g_puiElaps[ iPos ] = ( steady_clock::now() - g_tpStart ).count();
}
}
};
// thread body by means of CVA
void thdCVA( int iMyId ) {
// Let's try condition_variable_any with a fake lock.
FakeLock fakeLock;
int iLast, iPos;
iLast = iPos = g_aiPos;
while ( iPos < g_iLoops ) {
if ( ( iPos & 1 ) == iMyId ) {
// phase 1 : as a sender
// sleep a little while to ensure the peer has been listenning
this_thread::sleep_for( 1us );
g_tpStart = steady_clock::now();
asm volatile( "mfence":::"memory" );
g_aiPos.store( ( iLast = ++iPos ), memory_order_release );
g_cvaPing.notify_one();
} else {
// phase 0 : as a listenner
g_cvaPing.wait( fakeLock );
iPos = g_aiPos.load( memory_order_acquire );
asm volatile( "mfence":::"memory" );
/* calculate only when iPos has been changed, since we might be
* waked spuriously or the timeout hitted.
*/
if ( iPos > iLast && iPos < g_iLoops )
g_puiElaps[ iPos ] = ( steady_clock::now() - g_tpStart ).count();
}
}
};
// thread body by means of Semaphore
void thdSem( int iMyId ) {
int iLast, iPos;
iLast = iPos = g_aiPos;
while ( iPos < g_iLoops ) {
if ( ( iPos & 1 ) == iMyId ) {
// phase 1 : as a sender
// sleep a little while to keep fairness with thdCV
this_thread::sleep_for( 1us );
g_tpStart = steady_clock::now();
asm volatile( "mfence":::"memory" );
g_aiPos.store( ( iLast = ++iPos ), memory_order_release );
sem_post( iMyId == 1 ? & g_semPing : & g_semPong );
} else {
// phase 0 : as a listenner
sem_wait( iMyId == 0 ? & g_semPing : & g_semPong );
iPos = g_aiPos.load( memory_order_acquire );
asm volatile( "mfence":::"memory" );
if ( iPos > iLast && iPos < g_iLoops )
g_puiElaps[ iPos ] = ( steady_clock::now() - g_tpStart ).count();
}
}
// notify the peer to exit
// sem_post( & g_semPing );
};
double avgOf( const uint64_t* puiValues, int iCount,
uint64_t& uiMax, uint64_t& uiMin );
double stdOf( const uint64_t* puiValues, int iCount, double dAvg );
int main( int argc, char** argv ) {
if ( argc < 2 ) {
cout << "Usage: " << argv[0] << " loop_count " << endl;
return EXIT_FAILURE;
}
g_iLoops = atoi( argv[1] );
g_upBuffer = make_unique<uint64_t[]>( g_iLoops );
g_puiElaps = g_upBuffer.get();
if ( sem_init( &g_semPing, 0, 0 ) || sem_init( &g_semPong, 0, 0 ) ) {
cerr << "Failure when create a semaphore." << endl;
return EXIT_FAILURE;
}
uint64_t uiMax, uiMin;
double dAvgElp, dStdDev;
g_aiPos = -1;
thread thd0( thdCVS, 0 );
this_thread::sleep_for( 1us );
thread thd1( thdCVS, 1 );
thd0.join();
thd1.join();
dAvgElp = avgOf( g_puiElaps, g_iLoops, uiMax, uiMin );
dStdDev = stdOf( g_puiElaps, g_iLoops, dAvgElp );
cout << std::fixed << std::setprecision( 3 )
<< "Avg of CV is :" << dAvgElp / 1000 << "us" << endl
<< "StD is:" << dStdDev / 1000 << "us" << endl
<< "Max delay is:" << uiMax / 1000 << "us" << endl
<< "Min delay is:" << uiMin / 1000 << "us" << endl
<< endl;
g_aiPos = -1;
thd0 = thread( thdCVA, 0 );
this_thread::sleep_for( 1us );
thd1 = thread( thdCVA, 1 );
thd0.join();
thd1.join();
dAvgElp = avgOf( g_puiElaps, g_iLoops, uiMax, uiMin );
dStdDev = stdOf( g_puiElaps, g_iLoops, dAvgElp );
cout << std::fixed << std::setprecision( 3 )
<< "Avg of CVA is :" << dAvgElp / 1000 << "us" << endl
<< "StD is:" << dStdDev / 1000 << "us" << endl
<< "Max delay is:" << uiMax / 1000 << "us" << endl
<< "Min delay is:" << uiMin / 1000 << "us" << endl
<< endl;
g_aiPos = -1;
thd0 = thread( thdSem, 0 );
this_thread::sleep_for( 1us );
thd1 = thread( thdSem, 1 );
thd0.join();
thd1.join();
dAvgElp = avgOf( g_puiElaps, g_iLoops, uiMax, uiMin );
dStdDev = stdOf( g_puiElaps, g_iLoops, dAvgElp );
cout << std::fixed << std::setprecision( 3 )
<< "Avg of sem is :" << dAvgElp / 1000 << "us" << endl
<< "StD is:" << dStdDev / 1000 << "us" << endl
<< "Max delay is:" << uiMax / 1000 << "us" << endl
<< "Min delay is:" << uiMin / 1000 << "us" << endl
<< endl;
sem_destroy( &g_semPing );
return EXIT_SUCCESS;
};
double avgOf( const uint64_t* puiValues, int iCount,
uint64_t& uiMax, uint64_t& uiMin ) {
double dTotal = uiMin = uiMax = puiValues[0];
for ( int i = 1; i < iCount; ++i ) {
dTotal += puiValues[i];
uiMax = std::max<uint64_t>( uiMax, puiValues[i] );
uiMin = std::min<uint64_t>( uiMin, puiValues[i] );
}
return dTotal / iCount;
};
double stdOf( const uint64_t* puiValues, int iCount, double dAvg ) {
double dDiff, dSum = 0;
for ( int i = 0; i < iCount; ++i ) {
dDiff = puiValues[i] - dAvg;
dSum += dDiff * dDiff;
}
return std::sqrt( dSum / iCount );
};

Compiling two programs fails

For an assignment I have written two programs.
One for generating a file of random integers, the other for counting integers less than a specified threshold.
You can find the actual assignment texts below the code I've posted.
When compiling g++ generate.cpp -o generate, I get this error:
z1755294#hopper:~/assign2$ g++ generate.cpp -o generate
generate.cpp: In function ‘bool writeRand(int, int, int, const char*)’:
generate.cpp:12:31: error: variable ‘std::ofstream fout’ has initializer but incomplete type
ofstream fout ( fname );
When I compile g++ thresh.cpp -o thresh, I get this error:
z1755294#hopper:~/assign2$ g++ thresh.cpp -o thresh
thresh.cpp: In function ‘int main()’:
thresh.cpp:19:16: error: variable ‘std::ifstream fin’ has initializer but incomplete type
ifstream fin( fname.c_str() );
Can anyone help me fix my code to get it working? Also I need to create a Makefile for my project since I have multiple executables?
Thanks so much...kinda stuck on what to do.
This is my code:
generate.cpp
#include <iostream>
#include <cstdlib> // re. atoi
using std::cout;
using std::endl;
using std::cerr;
using std::ifstream;
using std::ofstream;
bool writeRand ( const int ranSeed, const int maxVal, const int numVals, const char* fname )
{
ofstream fout ( fname );
if ( fout )
{
srand ( ranSeed );
for ( int i=0; i < numVals; ++ i )
fout << rand () % (maxVal+1) << endl;
fout.close ();
return true;
}
//else
return false;
}
int main ( int argc, char* argv [] )
{
if (argc !=5 )
{
cerr << "Usage: " << argv[0] << "ranSeed maxVal numVals outFileName" << endl;
return -1;
}
const int ranSeed = atoi(argv[1]);
const int maxVal = atoi(argv[2]);
const int numVals = atoi(argv[3]);
const char* fname = argv[4];
if ( ranSeed <= 0 || maxVal <= 0 || numVals <= 0 )
{
cerr << "Invalid negative or zero numbers on command line....Try again..." << endl;
return -1;
}
if ( writeRand( ranSeed, maxVal, numVals, fname ) )
cout << "ranSeed = " << ranSeed << ", maxVal = " << maxVal << ", numVals = " << numVals
<< "\nfame " << fname << " was created ok ..." << endl;
else
cout << "There was a problem creating file " << fname << " ..." << endl;
}
thresh.cpp
#include <iostream>
#include <cstdlib> // re. atoi
using std::cout;
using std::endl;
using std::cin;
using std::ifstream;
using std::string;
using std::flush;
int main ()
{
//prompt and take in the desired file name
cout << "Enter name of file (for example randNums.txt): " << flush;
string fname;
getline( cin, fname );
//then can open file
ifstream fin( fname.c_str() );
if( fin )
{
int max, count = 0, below = 0, val = 0;
string line;
while( true )
{
cout << "Enter the threshold value: " << flush;
getline( cin,line );
max = atoi( line.c_str() );
if( max > 0 ) break;
cout << "Try again with value > 0 \n";
}
while( getline( fin, line) )
{
val = atoi( line.c_str() );
++count;
if( val < max ) ++below;
}
fin.close();
cout << below << " of " << count << " values in file '"
<< fname << "' are less than " << max << '\n';
max = val+1; //last value (in file) + 1
count = 0, below = 0;
fin.open( fname.c_str() );
while( getline( fin, line ) )
{
int val = atoi( line.c_str() );
++count;
if( val < max ) ++below;
}
fin.close();
cout << below << " of " << count << " values in file '"
<< fname << "' are less than " << max << '\n';
}
else
cout << "There was an error opening file " << fname << '\n';
cout << "Please 'Enter' to continue/exit..." << flush;
cin.get();
return 0;
}
Assignments
generate
Create a program called "generate" which generates a file of random integers.
This program takes four command line arguments. They are, in order
*A random number seed. This is an integer value explained below.
*A maximum value. The random values should be less than this maximum. This value is an integer.
*The number of values to be generated
*The name of an output file to store the values
If the command line arguments are not given, the program should give a brief message on proper usage and then exit. The integer values on the comand line should all be checked for negative values. If a negative value is given, the program should print an error message and exit.
Random number generation
The rand() function, found in returns a random positive integer every time it is called. The srand(int) function takes an integer called the random number seed which is used to initialize the random number generator. Subsequent calls to rand() produce a random sequence which is uniquely tied to its seed. Typically in a program, srand() is called once, while rand() is called multiple times.
A common technique for producing random numbers of a particular size is to use the remainder of divding rand() by the maximum upper bound.
thresh
Create a program called thresh which should ask the user for a file name and an integer threshold value. The program should then count the number of values in the file less than the threshold and report the results.
For example, 43 of 300 values in mydatafile are less than 17
This program should not use command line arguments. Rather, needed values should be obtained by prompting the user.
When asking for the threshold value, if the user inputs a negative value, the program should print an error and loop on the request until a proper value is obtained.
If the input file does not exist, an error message should be printed and the program should exit.
Hints:
Test your programs with small values that can be checked by hand. For example, create a file of 20 values less than 10. A particularly good test of thresh is to use the last value of the data file as a threshold value. Then use the last value plus one as a threshold value.
**A Makefile is required as part of your submission. If the project has multiple executables, you should have a default makefile rule to build all of the executables. You should have a rule to clear out the project to a pristine state. Your Makefile should use appropriate variables.
As #mrunion pointed out, you should replace
g++ generate.cpp thresh.cpp
with g++ generate.cpp
and g++ thresh.cpp
By the way, if you do these back to back, you'll overwrite your executable. An improvement would be:
g++ generate.cpp -o generate
and
g++ thresh.cpp -o thresh

Issues with variable used in reading binary file

I'm writing some serial port code and need to read the contents of a file (in binary) to a variable.
Starting from the example for "Binary files" at http://www.cplusplus.com/doc/tutorial/files/ ,
I try opening a .jpg file:
#include <iostream>
#include <fstream>
using namespace std;
ifstream::pos_type size;
char * memblock;
int main () {
ifstream file ("example.jpg", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << memblock << endl;
delete[] memblock;
}
else cout << "Unable to open file";
return 0;
}
However, only the first 4 characters (32 bits) are printed in the console.
What's particularly odd though is that using ostream::write() with that supposedly faulty variable "memblock" works perfectly:
ofstream fileOut ("writtenFile.jpg",ios::out|ios::binary);
fileOut.write(memblock,size);
fileOut.close();
ie it creates a new .jpg file.
So my question is why the memblock variable seems to only contain the first 4 characters.
There is probably a 0 in your binary data. cout is a text stream so looks at memblock as a string. If it reaches a null character then it thinks the string has finished.
See this for some help pin outputting binary data:
How to make cout behave as in binary mode?
Hmmm. A quick glance at the page you cite shows that the author doesn't
know much about IO in C++. Avoid it, since much of what it says is
wrong.
For the rest: .jpg is not a text format, and cannot be simply output
to cout. When you use <<, of course, the output stops at the first
'\0' character, but all sorts of binary data may cause wierd effects:
data may be interpreted as an escape sequence repositionning the cursor,
locking the keyboard (actually happened to me once), etc. These
problems will occur even if you use std::cout.write() (which will not
stop at the '\0' character). If you want to visualize the data,
your best bet is some sort of binary dump. (I use something like the
following for visualizing large blocks of data:
template <typename InputIterator>
void
process(
InputIterator begin,
InputIterator end,
std::ostream& output = std::cout )
{
IOSave saveAndRestore( output ) ;
output.setf( std::ios::hex, std::ios::basefield ) ;
output.setf( std::ios::uppercase ) ;
output.fill( '0' ) ;
static int const lineLength( 16 ) ;
while ( begin != end ) {
int inLineCount = 0;
unsigned char buffer[ lineLength ] ;
while ( inLineCount != lineLength && begin != end ) {
buffer[inLineCount] = *begin;
++ begin;
++ inLineCount;
}
for ( int i = 0 ; i < lineLength ; ++ i ) {
static char const *const
separTbl [] =
{
" ", " ", " ", " ",
" ", " ", " ", " ",
" ", " ", " ", " ",
" ", " ", " ", " ",
} ;
output << separTbl[ i ] ;
if ( i < inLineCount ) {
output << std::setw( 2 )
<< static_cast< unsigned int >(buffer[ i ] & 0xFF) ) ;
} else {
output << " " ;
}
}
output << " |" ;
for ( int i = 0 ; i != inLineCount ; ++ i ) {
output << (i < lengthRead && isprint( buffer[ i ] )
? static_cast< char >( buffer[ i ] )
: ' ') ;
}
output << '|' << std::endl ;
}
}
(You'll also want to read into an std::vector<char>, so you don't have
to worry about freeing the memory.)

C++:boost file system to return a list of files older than a specific time

I am using the Boost::FileSystem library with C++ running under Linux platform and I have a question following:
I would like to have a list of files which are modified older than a given date time. I don't know whether the boost::FileSystem offer such a method as:
vector<string> listFiles = boost::FileSystem::getFiles("\directory", "01/01/2010 12:00:00");
If yes, could you please provide sample code?
Boost::filesystem doesn't offer a function exactly like that. But you can use this:
http://www.boost.org/doc/libs/1_45_0/libs/filesystem/v3/doc/reference.html#last_write_time
as a basis to write your own. Here is some sample code using last_write_time:
#include <boost/filesystem/operations.hpp>
#include <ctime>
#include <iostream>
int main( int argc , char *argv[ ] ) {
if ( argc != 2 ) {
std::cerr << "Error! Syntax: moditime <filename>!\n" ;
return 1 ;
}
boost::filesystem::path p( argv[ 1 ] ) ;
if ( boost::filesystem::exists( p ) ) {
std::time_t t = boost::filesystem::last_write_time( p ) ;
std::cout << "On " << std::ctime( &t ) << " the file " << argv[ 1 ]
<< " was modified the last time!\n" ;
std::cout << "Setting the modification time to now:\n" ;
std::time_t n = std::time( 0 ) ;
boost::filesystem::last_write_time( p , n ) ;
t = boost::filesystem::last_write_time( p ) ;
std::cout << "Now the modification time is " << std::ctime( &t ) << std::endl ;
return 0 ;
} else {
std::cout << "Could not find file " << argv[ 1 ] << '\n' ;
return 2 ;
}
}
You can use a std::map(last_write_time, fileName) to store the file last modified time and the absolute file path and the do an in-order traversal to sort the data.

C++ converting a mac id string into an array of uint8_t

I want to read a mac id from command line and convert it to an array of uint8_t values to use it in a struct. I can not get it to work. I have a vector of string for the mac id split about : and I want to use stringstream to convert them with no luck. What I am missing?
int parseHex(const string &num){
stringstream ss(num);
ss << std::hex;
int n;
ss >> n;
return n;
}
uint8_t tgt_mac[6] = {0, 0, 0, 0, 0, 0};
v = StringSplit( mac , ":" );
for( int j = 0 ; j < v.size() ; j++ ){
tgt_mac[j] = parseHex(v.at(j));
}
I hate to answer this in this fashion, but sscanf() is probably the most succinct way to parse out a MAC address. It handles zero/non-zero padding, width checking, case folding, and all of that other stuff that no one likes to deal with. Anyway, here's my not so C++ version:
void
parse_mac(std::vector<uint8_t>& out, std::string const& in) {
unsigned int bytes[6];
if (std::sscanf(in.c_str(),
"%02x:%02x:%02x:%02x:%02x:%02x",
&bytes[0], &bytes[1], &bytes[2],
&bytes[3], &bytes[4], &bytes[5]) != 6)
{
throw std::runtime_error(in+std::string(" is an invalid MAC address"));
}
out.assign(&bytes[0], &bytes[6]);
}
Your problem may be in the output of the parsed data. The "<<" operator makes decisions on how to display data based on the data type passed it, and uint8_t may be getting interpretted as a char. Make sure you cast the array values to ints when printing, or investigate in a debugger.
The sample program:
uint8_t tgt_mac[6] = {0};
std::stringstream ss( "AA:BB:CC:DD:EE:11" );
char trash;
for ( int i = 0; i < 6; i++ )
{
int foo;
ss >> std::hex >> foo >> trash;
tgt_mac[i] = foo;
std::cout << std::hex << "Reading: " << foo << std::endl;
}
std::cout << "As int array: " << std::hex
<< (int) tgt_mac[0]
<< ":"
<< (int) tgt_mac[1]
<< ":"
<< (int) tgt_mac[2]
<< ":"
<< (int) tgt_mac[3]
<< ":"
<< (int) tgt_mac[4]
<< ":"
<< (int) tgt_mac[5]
<< std::endl;
std::cout << "As unint8_t array: " << std::hex
<< tgt_mac[0]
<< ":"
<< tgt_mac[1]
<< ":"
<< tgt_mac[2]
<< ":"
<< tgt_mac[3]
<< ":"
<< tgt_mac[4]
<< ":"
<< tgt_mac[5]
<< std::endl;
Gives the following output ( cygwin g++ )
Reading: aa
Reading: bb
Reading: cc
Reading: dd
Reading: ee
Reading: 11
As int array: aa:bb:cc:dd:ee:11
As unint8_t array: ª:»:I:Y:î:◄
First I want to point out that I think #Steven's answer is a very good one - indeed I noticed the same: the values are correct, but the output looks awkward. This is due to ostream& operator<<( ostream&, unsigned char ) being used, since the uint8_t type you used is a typedef for unsigned char (as I found in the linux man pages). Note that on VC++, the typedef isn't there, and you have to use unsigned __int8 instead (which will also route you to the char specialization).
Next, you can test your code like this (output-independent):
assert( uint8_t( parseHex( "00" ) ) == uint8_t(0) );
assert( uint8_t( parseHex( "01" ) ) == uint8_t(1) );
//...
assert( uint8_t( parseHex( "ff" ) ) == uint8_t(255) );
In addition to Steven's answer, I just want to point out the existence of the transform algorithm, which could still simplify your code.
for( int j = 0 ; j < v.size() ; j++ ){
tgt_mac[j] = parseHex(v.at(j));
}
Writes in one line:
std::transform( v.begin(), v.end(), tgt_mac, &parseHex );
(And I know that hasn't to do with the question...)
(See codepad.org for what it then looks like)
I think you are using the std::hex in the wrong place:
#include <sstream>
#include <iostream>
int main()
{
std::string h("a5");
std::stringstream s(h);
int x;
s >> std::hex >> x;
std::cout << "X(" << x << ")\n";
}