_ttoi win c++ assertion failure - c++

i have this code:
BOOLEAN Recurse = FALSE;
DWORD NumPasses = 1;
int _tmain( int argc, TCHAR *argv[] )
{
BOOL foundFileArg = FALSE;
int i;
if( argc < 2 ) {
return Usage( argv[0] );
}
for( i = 1; i < argc; i++ ) {
if( !_tcsicmp( argv[i], TEXT("/s") ) ||
!_tcsicmp( argv[i], TEXT("-s") )) {
Recurse = TRUE;
} else if( !_tcsicmp( argv[i], TEXT("/p") ) ||
!_tcsicmp( argv[i], TEXT("-p") )) {
// assertion failure
NumPasses = argc > i ? _ttoi( argv[i+1] ) : 1;
if( !NumPasses ) return Usage( argv[0] );
i++;
} else {
if( foundFileArg ) return Usage( argv[0] );
foundFileArg = TRUE;
}
}
return 0;
}
i get assertion failure,
Please suggest where the problem might be and where to look. Is it some problem with _ttoi function i'm using when it fails,
if i have to allocate a buffer,
how can i resolve it
thanks

this line
NumPasses = argc > i ? _ttoi( argv[i+1] ) : 1;
should be
NumPasses = argc > 1+i ? _ttoi( argv[i+1] ) : 1;

Nick is right; don't forget that arrays start at zero in C/C++. If there are 5 elements, it means argv[0] to argv[4] are valid - not argv[5].

Related

C++ MFC How to prevent duplicate values in each Ch?

I have the following code:
And I would like to select one Ch without the number which has been selected in the other Ch.
For example, in Ch5, "1","2","3","37" can not be selected.
BOOL CMaintenanceHeadDispenserDlg::OnInitDialog()
{
CMaintenanceChildDlg::OnInitDialog();
CRect rc(0, 0, 0, 0);
m_edtDist.Create( NULL, NULL, WS_CHILD|WS_VISIBLE|WS_DISABLED, rc, this, IDC_EDT_MT_HEAD_DISPENSER_DIST );
m_edtDist.SetInputMode( 1 );
m_edtDist.SetInputRange( 999.999, 0.0 );
m_edtDist.EnableRightInputMode( TRUE, 2 );
m_edtOutput.Create(NULL, WS_CHILD|WS_VISIBLE|WS_DISABLED, rc, this, IDC_EDT_MT_HEAD_DISPENSER_OUTPUT);
CDeviceConfigDispenserController* p = CDeviceConfigDispenserController::GetInstance();
SDeviceConfigDispenser d;
p->GetData( d );
m_DispenserChInfoSet.GetChMap(m_mapCh);
for( int i = 0; i < 5; i++ ) {
m_cmbCh[i].ResetContent();
m_cmbCh[i].SetScrollCnt(5);
m_cmbCh[i].SetHitTrace( TRUE );
m_edtCh[i].Create(NULL,NULL,WS_VISIBLE|WS_CHILD|WS_DISABLED,rc,this,IDC_EDT_MT_HEAD_DISPENSER_CH1 + i);
m_edtCh[i].SetLimitTextNum(32);
int itemCnt = 0;
CString strCh;
for( map<int, CString>::iterator it = m_mapCh.begin(); it != m_mapCh.end(); it++ ) {
strCh.Format(_T("%d"), it->first);
m_cmbCh[i].InsertString(itemCnt, strCh);
m_cmbCh[i].SetItemData(itemCnt, it->first);
if( d.nUseCh[i] == it->first ) {
m_cmbCh[i].SetCurSel( itemCnt );
m_edtCh[i].SetString( it->second );
}
itemCnt++;
}
m_rdoCh[i].SetCheck( BST_UNCHECKED );
}
afx_msg LRESULT CMaintenanceHeadDispenserDlg::OnCbxSelchanged(WPARAM wParam, LPARAM lParam)
{
//int j = 0; //ou
for( int i = 0; i < 5; i++ ) {
if( m_cmbCh[i].m_hWnd == (HWND)lParam )
{
int Cnt = m_cmbCh[i].GetCount();
if( (int)wParam < Cnt && (int)wParam >= 0) {
m_cmbCh[i].SetCurSel( (int)wParam );
int Index = (int)m_cmbCh[i].GetItemData( m_cmbCh[i].GetCurSel() );
map<int, CString>::iterator it = m_mapCh.find( Index );
if( it != m_mapCh.end() ) {
m_edtCh[i].SetString( it->second );
}
break;
}
}
}

Branching or ftell() that is Slowing?

I was viewing the file agents.h on my windows OS,and I wanted to see the c++ code without comments.i striped them out to see the code more clearly with my old program but i was surprised that it took like 2 seconds to finish.the size of the file is 605KB,so it isn't so bad.Why is it that slow.I suspect it is the function ftell() that is doing it,but i can't really tell.Is it branching that is slowing or ftell()?, if ftell(),then what is a better way to throw the FILE pointer back?
EDIT
#include <stdio.h>
#include <time.h>
#define NOT_COMMENT (!DOUBLESLASH_Comment && !ASTERISK_SLASH_Comment)
int main(int argc,char *argv[])
{
clock_t t1 = clock();
FILE *input , *output;
if( fopen_s(&input,argv[1],"r") )
{
printf("error opening file %s\n",argv[1]);
return 0;
}
if( fopen_s(&output,argv[2],"w") )
{
printf("error opening file %s\n",argv[2]);
return 0;
}
char c , d;
//escape flag
bool DOUBLESLASH_Comment = 0 , ASTERISK_SLASH_Comment = 0 , flag = 0;
/* single quotes / double quotes */
int s_QUOTED = 0 , d_QUOTED = 0;
while( (c=getc(input)) != EOF )
{
switch(c)
{
case '\\':
{
if( NOT_COMMENT )
{
if( flag == 1 )
flag = 0;
else
flag = 1;
}
}break;
case '\'':
{
if( NOT_COMMENT && !d_QUOTED )
{
if( !flag )
{
s_QUOTED++;
}
}
}break;
case '"':
{
if( NOT_COMMENT && !flag )
{
if( !s_QUOTED )
{
d_QUOTED++;
}
}
}break;
case '/':
{
if( NOT_COMMENT && !d_QUOTED )
{
if( (d=getc(input)) == '*' )
{
ASTERISK_SLASH_Comment = 1;
}
else if( d == '/' )
{
DOUBLESLASH_Comment = 1;
}
else
{
if( d != EOF )
{
ungetc(d,input);
}
}
}
}break;
case '*':
{
if( ASTERISK_SLASH_Comment )
{
if( (d=getc(input)) == '/')
{
if( (c=getc(input)) == EOF )
return 0;
ASTERISK_SLASH_Comment = 0;
}
else
{
if( d != EOF )
{
ungetc(d,input);
}
}
}
}break;
case '\n':
{
if( DOUBLESLASH_Comment )
{
DOUBLESLASH_Comment = 0;
}
}break;
}
if( NOT_COMMENT && c != '\\' ) flag = 0;
if( d_QUOTED == 2 ) d_QUOTED = 0;
if( s_QUOTED == 2 ) s_QUOTED = 0;
if( NOT_COMMENT )
{
fprintf(output,"%c",c);
}
}
fclose(input);
fclose(output);
clock_t t2 = clock();
double elapsed = (double)(t2 - t1) / CLOCKS_PER_SEC;
printf("time elapsed : %f\n",elapsed);
}
Without actually measuring the speed of your code in a profiler (and with the file you use as input, since one I use may have a different set of comments, etc that trigger a different behaviour), it's hard to say for sure. But it looks like you use fseek( ... ) simply to move back one character. In which case writing your own function for a one character lookahead would be a much better choice.
Something like this:
char lookahead = ' ';
bool havelookahead = false;
char getNextChar(FILE *input)
{
if (havelookahead)
{
havelookahead = false;
return lookahead;
}
return getc(input);
}
char peekChar(FILE *input)
{
if (!havelookahead)
{
lookahead = getc(input);
havelookahead = true;
}
return lookahead;
}
Then replace your getc with getNextChar in the beginning of the loop, and where you check the next character with peekChar (followed by a dummy getNextChar() to consume it).
This is a useful pattern in general for parsing - both at character level and at token level, so it's good learning to understand how this works.
You can also use the standard ungetc to "put back" your character that you looked at.
Whether this makes your code run significantly faster or not is hard to say, as I said in the beginning.
I cannot compile your code, so I cannot make tests. But I suspect that the bottleneck is fseek rather than ftell. Rejecting a character is a common task in parsing files... and should be implemented by the library or some intermediate layer with some buffering. In this case (rejection of a single character) you can use ungetc to achieve that.
So you should replace
fseek( file , ( ftell(file) - 1 ) , SEEK_SET );
with
ungetc('*', file); // ungetc('/', file); the second time.

C++ program opens file corectly on Linux but not on Windows

I compiled a Linux program on Windows via Mingw but the output is wrong.
Error description:
The output of the program looks different on Windows than on Linux. This is how it looks on Windows:
>tig_2
CAATCTTCAGAGTCCAGAGTGGGAGGCACAGACTACAGAAAATGAGCAGCGGGGCTGGTA
>cluster_1001_conTTGGTGAAGAGAATTTGGACATGGATGAAGGCTTGGGCTTGACCATGCGAAGG
Expected output:
>cluster_1001_contig2
CAATCTTCAGAGTCCAGAGTGGGAGGCACAGACTACAGAAAATGAGCAGCGGGGCTGGTA
>cluster_1001_contig1
TTGGTGAAGAGAATTTGGACATGGATGAAGGCTTGGGCTTGACCATGCGAAGG
(Note: the output is very large to paste it here so the examples above are pseudo-real).
Possible cause:
I have observed that if I convert the enter characters the input file from Linux (LF) to Windows (CRLF) it almost works: the first character (>) in file is missing. The same code works perfectly on Linux without any enter conversion. So, the problem must be in the function that is parsing the input not in the one that writes the output:
seq_db.Read( db_in.c_str(), options );
Source code:
This is the piece that is parsing the input file. Anyway, I might me wrong. The fault might be in other place. In case it is needed, the FULL source code is here :)
void SequenceDB::Read( const char *file, const Options & options )
{
Sequence one;
Sequence dummy;
Sequence des;
Sequence *last = NULL;
FILE *swap = NULL;
FILE *fin = fopen( file, "r" );
char *buffer = NULL;
char *res = NULL;
size_t swap_size = 0;
int option_l = options.min_length;
if( fin == NULL ) bomb_error( "Failed to open the database file" );
if( options.store_disk ) swap = OpenTempFile( temp_dir );
Clear();
dummy.swap = swap;
buffer = new char[ MAX_LINE_SIZE+1 ];
while (not feof( fin ) || one.size) { /* do not break when the last sequence is not handled */
buffer[0] = '>';
if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL && one.size == 0) break;
if( buffer[0] == '+' ){
int len = strlen( buffer );
int len2 = len;
while( len2 && buffer[len2-1] != '\n' ){
if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break;
len2 = strlen( buffer );
len += len2;
}
one.des_length2 = len;
dummy.des_length2 = len;
fseek( fin, one.size, SEEK_CUR );
}else if (buffer[0] == '>' || buffer[0] == '#' || (res==NULL && one.size)) {
if ( one.size ) { // write previous record
one.dat_length = dummy.dat_length = one.size;
if( one.identifier == NULL || one.Format() ){
printf( "Warning: from file \"%s\",\n", file );
printf( "Discarding invalid sequence or sequence without identifier and description!\n\n" );
if( one.identifier ) printf( "%s\n", one.identifier );
printf( "%s\n", one.data );
one.size = 0;
}
one.index = dummy.index = sequences.size();
if( one.size > option_l ) {
if ( swap ) {
swap_size += one.size;
// so that size of file < MAX_BIN_SWAP about 2GB
if ( swap_size >= MAX_BIN_SWAP) {
dummy.swap = swap = OpenTempFile( temp_dir );
swap_size = one.size;
}
dummy.size = one.size;
dummy.offset = ftell( swap );
dummy.des_length = one.des_length;
sequences.Append( new Sequence( dummy ) );
one.ConvertBases();
fwrite( one.data, 1, one.size, swap );
}else{
//printf( "==================\n" );
sequences.Append( new Sequence( one ) );
//printf( "------------------\n" );
//if( sequences.size() > 10 ) break;
}
//if( sequences.size() >= 10000 ) break;
}
}
one.size = 0;
one.des_length2 = 0;
int len = strlen( buffer );
int len2 = len;
des.size = 0;
des += buffer;
while( len2 && buffer[len2-1] != '\n' ){
if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break;
des += buffer;
len2 = strlen( buffer );
len += len2;
}
size_t offset = ftell( fin );
one.des_begin = dummy.des_begin = offset - len;
one.des_length = dummy.des_length = len;
int i = 0;
if( des.data[i] == '>' || des.data[i] == '#' || des.data[i] == '+' ) i += 1;
if( des.data[i] == ' ' or des.data[i] == '\t' ) i += 1;
if( options.des_len and options.des_len < des.size ) des.size = options.des_len;
while( i < des.size and ( des.data[i] != '\n') ) i += 1;
des.data[i] = 0;
one.identifier = dummy.identifier = des.data;
} else {
one += buffer;
}
}
#if 0
int i, n = 0;
for(i=0; i<sequences.size(); i++) n += sequences[i].bufsize + 4;
cout<<n<<"\t"<<sequences.capacity() * sizeof(Sequence)<<endl;
int i;
scanf( "%i", & i );
#endif
one.identifier = dummy.identifier = NULL;
delete[] buffer;
fclose( fin );
}
The format of the input file is like this:
> comment
ACGTACGTACGTACGTACGTACGTACGTACGT
> comment
ACGTACGTACGTACGTACGTACGTACGTACGT
> comment
ACGTACGTACGTACGTACGTACGTACGTACGT
etc
The issue is more than likely you need to open the file using the "rb" switch in the call to fopen. The "rb" opens the file in binary mode, as opposed to "r", which opens a file in "text" mode.
Since you're going back and forth between Linux and Windows, the end-of-line characters will be different. If you open the file as "text" in Windows, but the file was formatted for Linux, you're lying to Windows that it is a text file. So the runtime will do CR/LF conversion all wrong.
Therefore you should open the file as binary, "rb" so that the CR/LF translation isn't done.

Stack overflow in recursive function

I am writing a simple app that outputs all files in some directory to console. To achieve this I dynamically allocate memory in function PathCreator() and return a pointer to this memory. I don't know how to correctly free this memory segment in GetAllFiles(). When I use the code below I get a stack overflow exception. How can I fix this? Please don't offer me to use something that doesn't need dynamically allocated memory, I just want to fix my code.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName);
int is_directory(wchar_t *p)
{
wchar_t *t = PathCreator(p,L"\\");
WIN32_FIND_DATA file;
HANDLE search_hendle = FindFirstFile(t, &file);
long error = GetLastError();
if(error == 267)
{
return 0;
}
else
{
return 1;
}
}
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName)
{
wchar_t* path = 0;
int size = 0;
wchar_t *d = dir;
wchar_t *f = fileName;
while(*d != '\0')
{
d++;
size++;
}
while(*f != '\0')
{
f++;
size++;
}
path = new wchar_t[(size+=3) * sizeof(wchar_t)];
int j = 0;
while(j < size)
{
path[j] = '\0';
j++;
}
int i;
i = 0;
while(*dir != '\0')
{
path[i] = *dir;
i++;
dir++;
}
path[i++] = '\\';
wchar_t *t = fileName;
while(*t != '\0')
{
path[i] = *t;
i++;
t++;
}
path[i] = '\0';
return path;
}
void GetAllFiles(wchar_t* dir)
{
wchar_t *p = 0;
int i = 0;
WIN32_FIND_DATA file;
wchar_t *t = PathCreator(dir, L"*");
HANDLE search_hendle = FindFirstFile(t, &file);
if(search_hendle)
{
do
{
p = PathCreator(dir,file.cFileName);
if(!is_directory(p))
{
std::wcout << p << std::endl;
}
else
{
GetAllFiles(p);
}
delete [] p;
}
while(FindNextFile(search_hendle, &file));
}
delete [] t;
FindClose(search_hendle);
}
int _tmain(int argc, _TCHAR* argv[])
{
GetAllFiles(L"C:\\Users");
}
So, you have "." and ".." in your directory search.
The first entry is ".", so:
p = PathCreator(dir, file.cFilename)
yields:
"C:\Users\."
Then the next line:
if (!is_directory(p))
Is ALWAYS false, so it just keeps recursing into:
GetAllFiles(p)
forever ... or until your stack blows up, whichever comes first ;-)
I would recommend explicitly checking for "." and ".." and skipping those entries (also MFC and Qt, etc. have nice directory handling classes, but I think you want to do it this way).
My modification:
do
{
// I added this - guess I can't embolden code text
if (wcscmp(file.cFileName,L".") == 0 || wcscmp(file.cFileName,L"..")==0)
continue;
p = PathCreator(dir,file.cFileName);
if(!is_directory(p))
{
std::wcout << p << std::endl;
}
else
{
GetAllFiles(p);
}
delete [] p;
}
while(FindNextFile(search_hendle, &file));
Again you try to use C in place of C++ and you still using wcout?! no problem you are a programmer and I'm sure you have a reason for this! but memory management in C is much much harder than C++ and you should have some skills to use it. Here is a fully working code but as you see it is really harder to manage, use and understand than its C++ version using standard containers and string, so if you are allowed to use C++(as you use wcout) then use its C++ version for ease:
#include <Windows.h>
/*! \brief Merge \a folder and \a filename into a newly allocate memory and
* return it to the caller. Use free to free returned memory!
*/
wchar_t* PathCreator( wchar_t const* folder, wchar_t const* filename )
{
wchar_t* res;
size_t i, len, folderLen = wcslen( folder ), filenameLen = wcslen( filename );
len = folderLen + filenameLen;
if( folder[folderLen - 1] != '\\' ) ++len;
++len; // for \0
res = (wchar_t*) malloc( sizeof(wchar_t) * len );
if( !res ) return NULL;
wcscpy_s( res, len, folder );
/* Remove possible wide card at end of folder */
for( i = folderLen; i--; ) {
if( res[i] == '*' || res[i] == '?' ) {
res[i] = 0;
--folderLen;
} else {
break;
}
}
if( res[folderLen - 1] != '\\' ) wcscat_s( res, len, L"\\" );
wcscat_s( res, len, filename );
return res;
}
/*! \brief Free memory that returned by \ref GetAllFiles
*/
void FreeAllFilesMemory( wchar_t** p )
{
wchar_t** tmp = p;
if( !p ) return ;
while( *tmp ) free( *tmp++ );
free( p );
}
wchar_t** AddToArray( wchar_t** p, size_t* pAllocated, size_t* pUsed, wchar_t* s )
{
if( *pUsed >= *pAllocated ) {
size_t newAlloc = *pAllocated * 3 / 2; // Grow by 1.5
if( newAlloc < 16 ) newAlloc = 16;
p = (wchar_t**) realloc( p, newAlloc * sizeof(wchar_t*) );
if( !p ) return NULL;
*pAllocated = newAlloc;
}
p[*pUsed] = s;
++*pUsed;
return p;
}
wchar_t** GetAllFilesImpl( wchar_t const* folder, wchar_t** res, size_t* pAllocated, size_t* pUsed )
{
HANDLE hSearch;
WIN32_FIND_DATAW fileinfo;
size_t allocatedMemory = 0;
hSearch = FindFirstFileW( folder, &fileinfo );
if( hSearch != INVALID_HANDLE_VALUE ) {
do {
wchar_t* sFileName, ** tmp, sTmp[ 1024 ];
/* ignore ., .. */
if( !wcscmp(fileinfo.cFileName, L".") ||
!wcscmp(fileinfo.cFileName, L"..") )
continue;
sFileName = PathCreator( folder, fileinfo.cFileName );
wprintf( L"%s\n", sFileName ); /* Print result */
tmp = AddToArray( res, pAllocated, pUsed, sFileName );
if( !tmp ) return FreeAllFilesMemory(res), NULL;
res = tmp;
if( fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
wcscpy_s( sTmp, sFileName );
wcscat_s( sTmp, L"\\*" );
tmp = GetAllFilesImpl( sTmp, res, pAllocated, pUsed );
if( !tmp ) return NULL;
res = tmp;
}
} while( FindNextFileW(hSearch, &fileinfo) );
FindClose( hSearch );
}
return res;
}
/*! \brief List all files that match a pattern and return it as an array of
* wide strings, free result using \ref FreeAllFilesMemory
*/
wchar_t** GetAllFiles( wchar_t const* folder )
{
size_t nAllocated = 0, nUsed = 0;
wchar_t** res = GetAllFilesImpl( folder, NULL, &nAllocated, &nUsed );
if( res ) {
/* to indicate end of result add a NULL string */
wchar_t** tmp = AddToArray( res, &nAllocated, &nUsed, NULL );
if( !tmp ) return FreeAllFilesMemory(res), NULL;
res = tmp;
}
return res;
}

Determine if an number (encoded as a string) will fit in a 64-bit integer in C++?

I'm looking for a portable way to a) convert a string to a 64-bit signed integer (int64_t), and b) determine if it won't fit (overflows). Is there any way to do this?
strtoll is pretty portable anymore. And if not in your case, you could always crib the GNU C runtime library and add that to your project...
errno = 0;
long long val = strtoll (string, NULL, 0);
if (errno == ERANGE)
// there was an overflow conversion error
Run through the characters of the string one at a time and make your integer. if the character you're parsing will cause an overflow, then you know you're about to overflow. this code is the basic idea- doesn't handle errors or negative numbers, but should give you the idea...
bool ConvertToInt( const char* inString, int64_t& outInt )
{
int64_t kInt64Max = 0x7fffffffffffffff;
const char* c = inString;
outInt = 0;
while( *c != '\0' )
{
int charValue = *c - '0';
//outInt will be assigned outInt * 10 + charValue, so to check if that will overflow
//use algebra and move stuff around so that you can do the math without overflowing
if( outInt > ( kInt64Max - charValue ) / 10 )
{
//overflow
return false;
}
outInt = outInt * 10 + charValue;
++c;
}
return true;
}
if you want full credit on your homework, make sure to handle negative numbers and non-numeric characters. [ Edited to increment c ptr- thanks for the tip :) )
So a 'long long'? An signed int64_ can hold from –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, and you can just see that from the string. For example, with std::string:
int stringLength;
string myString("123456789");
stringLength = myString.length();
That code gets the length of your string. To determine whether it overflows just check the number of digits, and if there might be an overflow, check the first digit. To convert to int64_, use casting:
http://www.learncpp.com/cpp-tutorial/44-type-conversion-and-casting/
That link should answer your question. (However it's for C-style strings.) And one last clarification, is your string a std::string or not?
To cater for Visual C++ 10.0 (as I write this 11.0 is in beta), which apparently does not have strtoll or any equivalent,
#include <assert.h> // assert
#include <errno.h> // errno
#include <stdint.h> // int64_t
#include <string> // std::string
#include <stdexcept> // std::runtime_error, std::range_error
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, strtoll
#include <iostream>
using namespace std;
#if defined( _MSC_VER )
# if _MSC_VER <= 1600
# include <ole2.h>
inline long long strtoll( char const *str, char **str_end, int base )
{
assert(( "Only base 10 for Visual C++ 10 and earlier", base == 10 ));
std::wstring const ws( str, str + strlen( str ) );
LONG64 result;
HRESULT const hr = VarI8FromStr(
ws.c_str(), 0, LOCALE_NOUSEROVERRIDE, &result
);
switch( hr )
{
case S_OK:
if( str_end != 0 )
{
*str_end = const_cast<char*>( str + strlen( str ) );
}
return result;
case DISP_E_OVERFLOW:
errno = ERANGE;
if( str_end != 0 )
{
*str_end = const_cast<char*>( str );
}
return (*str == '-'? LLONG_MIN : LLONG_MAX);
default:
errno = EILSEQ;
if( str_end != 0 )
{
*str_end = const_cast<char*>( str );
}
return 0;
}
}
# endif
#endif
template< class Type >
bool hopefully( Type const& v ) { return !!v; }
bool throwX( string const& s ) { throw runtime_error( s ); }
bool throwRangeX( string const& s ) { throw range_error( s ); }
int64_t int64From( string const& s )
{
errno = 0;
int64_t const result = strtoll( s.c_str(), nullptr, 10 );
if( errno == ERANGE )
throwRangeX( "int64From: specificed nr too large" );
else if( errno != 0 )
throwX( "int64From: parsing failed" );
return result;
}
int main( int argc, char** argv )
{
try
{
int64_t const x = int64From( argv[argc - 1] );
wcout << x << endl;
return EXIT_SUCCESS;
}
catch( runtime_error const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
Then for Visual C++ 10 and earlier, link with [oleaut32.lib].
I tested this with MinGW g++ and Visual C++.
PS: Alternatively you can just an istringstream, but it does not reliably tell you why it failed when it fails – and it seems to be a requirement to detect overflow as such.
Based on a helpful response from Joshua Glazer, I came up with the following solution which does error checking and also works for negative integers:
#define __STDC_LIMIT_MACROS
#include <stdint.h>
// convert a string to an integer, return whether successful
bool string_to_int(string in, int64_t &out) {
size_t pos = 0;
if (in.size() == 0)
return false;
if (in[pos] == '+')
pos++;
out = 0;
if (in[pos] == '-') {
pos++;
while (pos < in.size()) {
if (in[pos] < '0' || in[pos] > '9')
return false;
int c = in[pos]-'0';
if (out < (INT64_MIN+c)/10)
return false;
out = out*10-c;
pos++;
}
} else {
while (pos < in.size()) {
if (in[pos] < '0' || in[pos] > '9')
return false;
int c = in[pos]-'0';
if (out > (INT64_MAX-c)/10)
return false;
out = out*10+c;
pos++;
}
}
return true;
}