Am trying to use functions from a dll file i built in c++ in c#; below is the c++ .h codes
#pragma once
#pragma unmanaged
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
#include <list>
#include <string>
using namespace std;
extern "C"
{
string DLLIMPORT encrypt(string keeper);
string DLLIMPORT decrypt(string keeper);
}
#endif /* _DLL_H_ */
the c++ .cpp codes are below
#pragma managed
#include "cenH.h"
#include <windows.h>
#include <iostream>
using namespace std;
const char alphabets[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v','w','x','y','z'};
string encrypt(string keeper)
{
string keep;
string m = keeper;
cout << keeper.length() << endl;
for(int count = 0; count < m.length(); count++)
{
for(int c = 0; c < 26; c++)
{
if(m[count] == alphabets[c])
{
int counter = c - 8;
if(counter < 0)
{
counter = counter + 26;
keep += alphabets[counter];
}
else
{
keep += alphabets[counter];
}
}
else if(m[count] == ' ')
{
keep+=".";
break;
}
}//end of second loop
//end first loop
cout << keep << endl;
return keep;
}
string decrypt(string keeper)
{
//cout << "\n" << endl;
string keep;
string m = keeper;
for(int count = 0; count < m.length(); count++)
{
for(int c = 0; c < 26; c++)
{
if(m[count] == alphabets[c])
{
int counter = c + 8;
if(counter >= 26)
{
counter = counter - 26;
keep += alphabets[counter];
}
else
{
keep += alphabets[counter];
}
}else if(m[count] == '.')
{
keep+=" ";
break;
}
}//end of third loop
}//end second loop
//cout << keep << endl;
return keep;
}
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
i compile this codes and they dont give errors, i even test run them in a c++ console app by calling the dll file and it works fine but when i call this dll file into my c# programs it give me the AccessViolationException Attempted to read or write protected memory. This is often an indication that other memory is corrupt. The dll is complied in the MinGW GCC 4.6.2 32-bit and my c# runs on x86(32-bit).can someone please point to me what i have done wrong.
This is how i imported the dll inside my c# code
[DllImport("cen.dll",CallingConvention = CallingConvention.StdCall)]
internal static extern string decrypt(String keeper);
string line = decrypt("savethemonkeys");
Related
I am analyzing an implementation of a queue (implemented using a circular buffer) which is supposed to be used by 1 consumer and n producers. This code is a porting of a C# implementation you can find here.
The code below shows the implementation of such a queue, and a main. On my system, this program crashes. I narrowed down the problem to the fact that the pop() function is returning a reference. Such reference is an alias for the array cell and not for the pointer the cell of the array contains. This reference is then used to execute the task, but crucially, some producers might write in the same array location and the whole program goes UB. Am I completely going in the wrong direction here?
Of course, if I remove the & form the signature the program works fine with no crashes.
I have also used helgrind to check for race conditions and indeed when I run the reference version it shows a warning.
#include <cmath>
#include <functional>
#include <iostream>
#include <mutex>
#include <stdexcept>
#include <thread>
template<typename T, uint64_t SIZE = 4096, uint64_t MAX_SPIN_ON_BUSY = 40000000>
class ConcurrentQueue {
private:
static constexpr unsigned Log2(unsigned n, unsigned p = 0) {
return (n <= 1) ? p : Log2(n / 2, p + 1);
}
static constexpr uint64_t closestExponentOf2(uint64_t x) {
return (1UL << ((uint64_t) (Log2(SIZE - 1)) + 1));
}
static constexpr uint64_t mRingModMask = closestExponentOf2(SIZE) - 1;
static constexpr uint64_t mSize = closestExponentOf2(SIZE);
static const T mEmpty;
T mMem[mSize];
std::mutex mLock;
uint64_t mReadPtr = 0;
uint64_t mWritePtr = 0;
public:
const T& pop() { //piece of code I believe is dangerous
if (!peek()) {
return mEmpty;
}
std::lock_guard<std::mutex> lock(mLock);
if (!peek()) {
return mEmpty;
}
T& ret = mMem[mReadPtr & mRingModMask];
mReadPtr++;
return ret;
}
bool peek() const {
return (mWritePtr != mReadPtr);
}
uint64_t getCount() const {
return mWritePtr > mReadPtr ? mWritePtr - mReadPtr : mReadPtr - mWritePtr;
}
bool busyWaitForPush() {
uint64_t start = 0;
while (getCount() == mSize) {
if (start++ > MAX_SPIN_ON_BUSY) {
return false;
}
}
return true;
}
void push(const T& pItem) {
if (!busyWaitForPush()) {
throw std::runtime_error("Concurrent queue full cannot write to it!");
}
std::lock_guard<std::mutex> lock(mLock);
mMem[mWritePtr & mRingModMask] = pItem;
mWritePtr++;
}
void push(T&& pItem) {
if (!busyWaitForPush()) {
throw std::runtime_error("Concurrent queue full cannot write to it!");
}
std::lock_guard<std::mutex> lock(mLock);
mMem[mWritePtr & mRingModMask] = std::move(pItem);
mWritePtr++;
}
};
template<typename T, uint64_t SIZE, uint64_t MAX_SPIN_ON_BUSY>
const T ConcurrentQueue<T, SIZE, MAX_SPIN_ON_BUSY>::mEmpty = T{ };
int main(int, char**) {
using Functor = std::function<void()>;
ConcurrentQueue<Functor*> queue;
std::thread consumer([ & ] {
while (true) {
if (queue.peek()) {
auto task = queue.pop();
(*task)();
delete task;
}
}
});
std::thread producer([ & ] {
uint64_t counter = 0;
while (true) {
auto taskId = counter++;
auto newTask = new Functor([ = ] {
std::cout << "Running task " << taskId << std::endl << std::flush;
});
queue.push(newTask);
}
});
consumer.join();
producer.join();
return 0;
}
I'm having trouble with a problem, that I think is just a case of casting from unsigned char to char*. However, I've not managed to do it in a way that works!
What I'm doing is reading data in to a C++ program as an unsigned char [64]. This then needs to be transmitted over a TCP socket to a waiting C# TcpListener (I've also tried listening with netcat on linux, and Hurcules.
The listener (whichever one I use) receives nothing that makes sense!
If I char* buffer2 = reinterpret_cast<char*>(buffer); I get something transmitted, but it's nonsense, and when I inspect buffer2 during debug it contains only a "0".
Below is some stripped back C++ code for sending using my own SocketClient_Winsock class (which is even further down)
#include "stdafx.h"
#include "SocketClient_Winsock.h"
#include <iostream>
using namespace std;
void GetData(unsigned char *fillme)
{
// Fill the array!
for (int a = 0; a < 64; a++)
{
fillme[a] = a;
}
printf("in GetData: \n");
for (int a = 0; a < 64; a++)
printf("%i, ", fillme[a]);
printf("\n\n");
}
void SendData(char* sendme)
{
printf("in SendData: \n");
for (int a = 0; a < 64; a++)
printf("%i, ", sendme[a]);
printf("\n\n");
SocketClient_Winsock sock("127.0.0.1"); // Default constructor 127.0.0.1:5000
sock.Start();
//sock.Send("Incoming!\n");
sock.Send(sendme);
//sock.Send("Done.");
sock.Stop();
}
int _tmain(int argc, _TCHAR* argv[])
{
// Create the buffer
unsigned char buffer[64];
printf("Before filling: \n"); // output
for (int a = 0; a < 64; a++)
printf("%i, ", buffer[a]);
printf("\n\n");
// Fill the buffer
GetData(buffer);
printf("after filling: \n"); // output again
for (int a = 0; a < 64; a++)
printf("%i, ", buffer[a]);
printf("\n\n");
// Send data over TCP connection
SendData((char*)buffer);
// Output
printf("after sending: \n");
for (int a = 0; a < 64; a++)
printf("%i, ", buffer[a]);
printf("\n\n");
return 0;
}
And here is the SocketClient_Winsock.h:
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <algorithm>
// link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_PORT "5000"
#define DEFAULT_BUFLEN 512
using namespace std;
class SocketClient_Winsock
{
private:
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
//char *sendbuf = "this is a test"; // we expect this to be sent back from the class
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
char* serverName;
public:
SocketClient_Winsock();
SocketClient_Winsock(char* servername);
bool Start();
int Stop();
int Send(string);
int Send(char*);
int Send(unsigned char*);
bool Recv();
~SocketClient_Winsock();
};
And the SocketClient_Winsock.cpp:
#include "stdafx.h"
#include "SocketClient_Winsock.h"
#include <iostream>
// From https://msdn.microsoft.com/en-us/library/windows/desktop/ms737591(v=vs.85).aspx
SocketClient_Winsock::SocketClient_Winsock()
{
serverName = "127.0.0.1"; // Default to localhost
}
SocketClient_Winsock::SocketClient_Winsock(char * servername)
{
serverName = servername;
ConnectSocket = INVALID_SOCKET;
}
bool SocketClient_Winsock::Start() {
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(serverName, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
return true;
};
int SocketClient_Winsock::Stop()
{
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
return 0;
};
// Send message to server
int SocketClient_Winsock::Send(char* msg)
{
printf("during sending: \n");
for (int a = 0; a < 64; a++)
printf("%i, ", msg[a]);
printf("\n\n");
iResult = send(ConnectSocket, msg, (int)strlen(msg), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
return 0;
};
int SocketClient_Winsock::Send(std::string msg)
{
int iResult = send(ConnectSocket, msg.c_str(), msg.size(), 0);
if (iResult == SOCKET_ERROR)
{
printf("send failed: %d\n", WSAGetLastError());
Stop();
return false;
}
return 0;
};
// Receive message from server
bool SocketClient_Winsock::Recv()
{
char recvbuf[DEFAULT_BUFLEN];
int iResult = recv(ConnectSocket, recvbuf, DEFAULT_BUFLEN, 0);
if (iResult > 0)
{
std::string msg = std::string(recvbuf);
msg.erase(msg.find_first_of("\n"), msg.length()); // remove all characters after /n
std::cout << msg << std::endl;
return true;
}
return false;
}
SocketClient_Winsock::~SocketClient_Winsock()
{
// cleanup
closesocket(ConnectSocket);
WSACleanup();
}
And the C# Host:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace Receiver
{
class Program
{
static void Main(string[] args)
{
// now listen:
Int32 port = 5000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
TcpListener server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[64];
String data = null;
// Enter the listening loop.
while(true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
//stream.Write(msg, 0, msg.Length);
//Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
}
}
As MagikM18 commented below, the original solution was no solution at all... just a workaround to a bug.
The bug was in the C# side of things (which I ignored, thinking it was from the MSDN, it'll be fine. Don't do that!). It was taking my data and forcing it into ASCII - hence the nonsense. If I looked at the raw data all was fine.
So, my Send Data now looks like this:
int SocketClient_Winsock::Send(char* msg, int msgLength)
{
iResult = send(ConnectSocket, msg, msgLength, 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
return 0;
};
and is called by:
sock.Send((char*)buffer, BUFFER_LEN);
I just started using dlls, but I haven't had this problem before, so it might not be dll connected. I am have KMP String-match algorithm implemented in c++ and I am calling it from c# using dll.
This is my export:
extern "C" __declspec (dllexport) const char* naive(const char* text, const char* str);
extern "C" __declspec (dllexport) const char* KMP(const char* text, const char* str);
My import:
[DllImport(#"dll_path", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr KMP([MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string str);
Calling from c#
string output = Marshal.PtrToStringAnsi(KMP(richTextBox1.Text, richTextBox2.Text));
And the c++ function:
const char* KMP(const char* text, const char* str)
{
int tL = strlen(text);
int sL = strlen(str);
/* Algorithm */
}
The exception is thrown right after the function is called. So I figured it's not the code implementation. The wired thing is it's only thrown when there is a '\n' new line in the second parameter (str), no matter where exactly. If there are no new lines it runs normally. The thing that confuses me the most is why just the second argument, both are identically declared and used. I also have implemented Naive algorithm, same story.
All the answers I found were only when a negative number was given as size to an array or an undeclared variable, but nothing on pointers. But I doubt it's anything similar, because when my search string (2nd parameter (str)) doesn't contain new line the code executes normally.
Any ideas ?
Thank you in front.
EDIT (body of function):
const char* KMP(const char* text, const char* str)
{
int tL = strlen(text);
int sL = strlen(str);
string match = "";
if (sL == 0 || tL == 0)
throw "both text and string must be larger than 0";
else if (sL > tL)
throw "the text must be longer than the string";
int tI = 0;
int col = 0, row = 0;
while (tI <= tL - sL)
{
int i = 0;
int tmpCol = -1;
int next = 1;
for (; i <= sL && text[i + tI] != '\0'; i++)
{
if (text[i + tI] == '\n')
{
row++;
tmpCol++;
}
if (text[i + tI] == str[0] && next == 1 && i > 0)
next = i;
if (text[i + tI] != str[i])
break;
}
if (i == sL)
{
match += to_string(row) + ',' + to_string(col) + ';';
}
tI += next;
col = tmpCol > -1 ? tmpCol : col + next;
}
char* c = new char[match.length() - 1];
c[match.length() - 1] = '\0';
for (int i = 0; i < match.length() - 1; i++)
c[i] = match[i];
return c;
}
Just change your code to handle no matches case, because runtime cannot allocate 0-1 = 0xFFFFFFFFF bytes. And now I have also changed your copy buffer allocation and loop code to avoid overwrite(as pointed by #HenkHoltermann):
...
if (match.length() == 0)
return "No matches";
// Allocate for all chars + \0 except the last semicolon
char* c = new char[match.length()];
c[match.length() - 1] = '\0';
// Copy all chars except the last semicolon
for (int i = 0; i < match.length() - 1; i++)
c[i] = match[i];
return c;
!It still does not copy the last semicolon, so if you need it then you will have to add one more symbol to the buffer.
P.S.: Also I see a few issues with your code:
You use C++ exceptions. While CLR will catch them as SEH (because VC++ uses SEH) it is still not a good idea overall - Throwing C++ exceptions across DLL boundaries
You use signed int for length int tL = strlen(text); and strlen returns unsigned size_t. It may not be an actual problem, but it is not a right way either.
This question already has answers here:
std::string formatting like sprintf
(44 answers)
Closed 7 years ago.
I don't have much experience working with C++. Rather I have worked more in C# and so, I wanted to ask my question by relating to what I would have done in there. I have to generate a specific format of the string, which I have to pass to another function. In C#, I would have easily generated the string through the below simple code.
string a = "test";
string b = "text.txt";
string c = "text1.txt";
String.Format("{0} {1} > {2}", a, b, c);
By generating such an above string, I should be able to pass this in system(). However, system only accepts char*
I am on Win32 C++ (not C++/CLI), and cannot use boost since it would include too much inclusion of all the files for a project which itself is very small. Something like sprintf() looks useful to me, but sprintf does not accept string as the a, b and c parameters. Any suggestions how I can generate these formatted strings to pass to system in my program?
The C++ way would be to use a std::stringstream object as:
std::stringstream fmt;
fmt << a << " " << b << " > " << c;
The C way would be to use sprintf.
The C way is difficult to get right since:
It is type unsafe
Requires buffer management
Of course, you may want to fall back on the C way if performance is an issue (imagine you are creating fixed-size million little stringstream objects and then throwing them away).
For the sake of completeness, you may use std::stringstream:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string a = "a", b = "b", c = "c";
// apply formatting
std::stringstream s;
s << a << " " << b << " > " << c;
// assign to std::string
std::string str = s.str();
std::cout << str << "\n";
}
Or (in this case) std::string's very own string concatenation capabilities:
#include <iostream>
#include <string>
int main() {
std::string a = "a", b = "b", c = "c";
std::string str = a + " " + b + " > " + c;
std::cout << str << "\n";
}
For reference:
http://en.cppreference.com/w/cpp/string/basic_string/operator+
If you really want to go the C way, here you are:
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
int main() {
std::string a = "a", b = "b", c = "c";
const char fmt[] = "%s %s > %s";
// use std::vector for memory management (to avoid memory leaks)
std::vector<char>::size_type size = 256;
std::vector<char> buf;
do {
// use snprintf instead of sprintf (to avoid buffer overflows)
// snprintf returns the required size (without terminating null)
// if buffer is too small initially: loop should run at most twice
buf.resize(size+1);
size = std::snprintf(
&buf[0], buf.size(),
fmt, a.c_str(), b.c_str(), c.c_str());
} while (size+1 > buf.size());
// assign to std::string
std::string str = &buf[0];
std::cout << str << "\n";
}
For reference:
http://en.cppreference.com/w/cpp/io/c/fprintf
Since C++11, you can "simplify" this to:
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
int main() {
std::string a = "a", b = "b", c = "c";
const char fmt[] = "%s %s > %s";
// can use std::string as buffer directly (since C++11)
std::string::size_type size = 256;
std::string str;
do {
str.resize(size+1);
// use snprintf instead of sprintf (to avoid buffer overflows)
// snprintf returns the required size (without terminating null)
// if buffer is too small initially: loop should run at most twice
size = std::snprintf(
&str[0], str.size(),
fmt, a.c_str(), b.c_str(), c.c_str());
} while (size+1 > str.size());
// can strip off null-terminator, as std::string adds their own
str.resize(size);
// done
std::cout << str << "\n";
}
For reference:
Directly write into char* buffer of std::string
Then, there's the Boost Format Library. For the sake of your example:
#include <iostream>
#include <string>
#include <boost/format.hpp>
int main() {
std::string a = "a", b = "b", c = "c";
// apply format
boost::format fmt = boost::format("%s %s > %s") % a % b % c;
// assign to std::string
std::string str = fmt.str();
std::cout << str << "\n";
}
In addition to options suggested by others I can recommend the fmt library which implements string formatting similar to str.format in Python and String.Format in C#. Here's an example:
std::string a = "test";
std::string b = "text.txt";
std::string c = "text1.txt";
std::string result = fmt::format("{0} {1} > {2}", a, b, c);
Disclaimer: I'm the author of this library.
You can use sprintf in combination with std::string.c_str().
c_str() returns a const char* and works with sprintf:
string a = "test";
string b = "text.txt";
string c = "text1.txt";
char* x = new char[a.length() + b.length() + c.length() + 32];
sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
string str = x;
delete[] x;
or you can use a pre-allocated char array if you know the size:
string a = "test";
string b = "text.txt";
string c = "text1.txt";
char x[256];
sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
For completeness, the boost way would be to use boost::format
cout << boost::format("%s %s > %s") % a % b % c;
Take your pick. The boost solution has the advantage of type safety with the sprintf format (for those who find the << syntax a bit clunky).
As already mentioned the C++ way is using stringstreams.
#include <sstream>
string a = "test";
string b = "text.txt";
string c = "text1.txt";
std::stringstream ostr;
ostr << a << " " << b << " > " << c;
Note that you can get the C string from the string stream object like so.
std::string formatted_string = ostr.str();
const char* c_str = formatted_string.c_str();
You can just concatenate the strings and build a command line.
std::string command = a + ' ' + b + " > " + c;
system(command.c_str());
You don't need any extra libraries for this.
I'm trying to figure out how to get a string from an array starting at some given position. Say we have an array that's arbitrarily long and my string starts at location 1000. If I wanted to get a string from a file I would simply use something like getc or scanf or something. How do I carry out these same functions on an array instead of a file?
*oh, keep in mind that the array is of type int and is full of numerical representations of ASCII characters.
If you were dealing with a byte[] array then you could just do this:
string yourString = Encoding.ASCII.GetString(yourArray, startIndex, length);
Since your array is of type int[] then -- assuming that each element represents a single ASCII character -- you'll need to convert those ints to bytes first. If the array is "arbitrarily long" then you may not want to convert the whole thing to a byte[] array, in which case just convert the section that you need:
byte[] temp =
yourArray.Skip(startIndex).Take(length).Select(i => (byte)i).ToArray();
string yourString = Encoding.ASCII.GetString(temp);
If each element of your int[] array doesn't actually represent a single ASCII character then you'll need to give us more info about the precise format that it uses.
Assuming the string is null terminated (you don't specify how you know the end of the string) then a bit of Linq should do the trick:
var chars = ints.Skip(1000).TakeWhile(i => i != 0).Select(i => (char)i);
var str = new string(chars.ToArray());
The first like skips 1000 ints, takes them while they're not a null-terminator, and then converts them to a char as appropriate for ints representing ASCII codes. The second line simply makes them into a string.
If the string has no null terminator, and just ends when the array ends, then just remove the call to TakeWhile.
Here is an alternative (similar to the solution provided by LukeH) that might be faster (since it uses built in array methods rather than LINQ):
public static string GetString(int[] array, int startIndex, int length)
{
var subarray = new int[length];
Array.Copy(array, startIndex, subarray, 0, length);
return Encoding.ASCII.GetString(Array.ConvertAll(subarray, i => (byte)i));
}
Could you slice the elements from the array and call ASCIIEncoding.GetString() on it
LINQ can be pretty hand at times...
var ints = Enumerable.Range(0, 255).ToArray();
var start = 65;
var length = 26;
var value = new string(ints.Select(i => (char)i)
.Skip(start)
.Take(length)
.ToArray());
Console.WriteLine(value); //ABCDEFGHIJKLMNOPQRSTUVWXYZ
Here is my code just for reference. If you goto the "SYSCALL" section you will find an if statement pertaining to "open 4" this is where I'm stuck. Oh, by the way, I'm not using visual studio, I'm using a program called "Verilator" which allows me to interface Verilog Code with C++ code.
#include "VMIPS.h"
#include "VMIPS_MIPS.h"//required to explicitly access signals from submodules
#include <verilated.h>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <vector>
using namespace std;
unsigned int main_time = 0;
static inline int hexCharValue(char ch)
{
if (ch>='0' && ch<='9')return ch-'0';
if (ch>='a' && ch<='f')return ch-'a'+10;
return 0;
}
int main(int argc, char **argv)
{
///////////////////////////////////////// Instruction Capture /////////////////////////////////////////////
ifstream inClientFile( "TEXT.txt",ios::in ); //stream object
//test if instruction file can be opened
if ( !inClientFile )
{
cerr << "File couldn't be opened" << endl;
return 1; //no point using exit inside main
}
//fill string array with all file values and determines length of program
vector<string> words;
words.reserve(274815);
string word;
while (inClientFile >> word)words.push_back(word); //helper function is unnecessary
cout << "Number of words:" << words.size() << endl;
const int wordCount=words.size();
vector<int> InstructionMemory;
vector<string> tempInstructionMemory;
tempInstructionMemory.reserve(wordCount);
//cut out undesired strings from vector
for(int i=0; i<wordCount; i++)
{
if (words[i].length()==8 && words[i].find("fs24")==string::npos) //f0 can exist at pos 1 in a valid hex string
{
tempInstructionMemory.push_back(words[i]);
}
}
//convert string hex to numerical decimal
InstructionMemory.resize(tempInstructionMemory.size());
for( int j=0; j<tempInstructionMemory.size(); j++ )
{
for( int y=0; y<8; y++)
{
InstructionMemory[j]+=hexCharValue(tempInstructionMemory[j][y])<<(4*(7-y));//4194608+4*
}
}
//printf("Amortized Instruction Vector Size:%d\n",InstructionMemory.size());
////////////////////////////////////// Data Capture ////////////////////////////////////////////////
ifstream inClientDataFile( "DATA.txt",ios::in ); //stream object
//test if instruction file can be opened
if ( !inClientDataFile )
{
cerr << "File couldn't be opened" << endl;
return 1; //no point using exit inside main
}
//fill string array with all file values and determines length of program
vector<string> datas;
datas.reserve(274815);
string data;
while (inClientDataFile >> data)datas.push_back(data); //helper function is unnecessary
cout << "Number of data packets:" << datas.size() << endl;
const int dataCount=datas.size();
vector<int> DataMemory;
vector<string> tempDataMemory;
tempDataMemory.reserve(dataCount);
//cut out undesired strings from vector
for( int i=0; i<dataCount; i++)
{
if (datas[i].length()==8 && datas[i].find("fs24")==string::npos) //f0 can exist at pos 1 in a valid hex string
{
tempDataMemory.push_back(datas[i]);
}
}
//convert string hex to numerical decimal
DataMemory.resize(tempDataMemory.size());
for( int j=0; j<tempDataMemory.size(); j++ )
{
for( int y=0; y<8; y++)
{
DataMemory[j]+=hexCharValue(tempDataMemory[j][y])<<(4*(7-y));
}
}
//printf("Amortized Data Vector Size:%d\n",DataMemory.size());
/////////////////////////////////////////// MIPS I processor interface /////////////////////////////////////////////
Verilated::commandArgs(argc, argv);
VMIPS *top = new VMIPS;
top->CLK = 0;
vector<int> HS0,HS1,HS2;
vector<string> FDT_filename;
vector<int> FDT_state;//1 = open, 0 = closed
int FileDescriptorIndex = 3;//start of non-reserved indecies
FILE *f;
//first 3 positions reserved for stdin, stdout, and stderr
FDT_filename.push_back("stdin");
FDT_filename.push_back("stdout");
FDT_filename.push_back("stderr");
FDT_state.push_back(0);
FDT_state.push_back(0);
FDT_state.push_back(0);
//int FDT[100];
printf("IMAddr:%d IM:%d \n***************\n",top->Iaddr,InstructionMemory[(top->Iaddr)/4]);
while (!Verilated::gotFinish())
{
//clock generation
top->CLK=!(top->CLK);
//vector mapping
if ( ( top->Daddr >= 0 ) && ( top->Daddr <= 419604 ) )
{
if(top->MemRead)
top->Din = HS0[(top->Daddr)/4];
if(top->MemWrite)
HS0[(top->Daddr)/4] = top->Dout;
}
else if ( ( top->Daddr >= (419608+InstructionMemory.size()+4) ) && ( top->Daddr <= 268435452 ) )
{
if(top->MemRead)
top->Din = HS1[(top->Daddr-419608)/4];
if(top->MemWrite)
HS1[(top->Daddr-419608)/4] = top->Dout;
}
else if ( ( top->Daddr >= 268435456 ) && ( top->Daddr <= (268435456+DataMemory.size()) ) )
{
if(top->MemRead)
top->Din = DataMemory[(top->Daddr-2668435456)/4];
if(top->MemWrite)
DataMemory[(top->Daddr-2668435456)/4] = top->Dout;
}
else if ( top->Daddr >=(268435456+DataMemory.size()+4) )
{
if(top->MemRead)
top->Din = HS2[(top->Daddr-(268435456+DataMemory.size()+4))/4];
if(top->MemWrite)
HS2[(top->Daddr-(268435456+DataMemory.size()+4))/4] = top->Dout;
}
//instruction supply mapping
if ( top->Iaddr < 4194608 )
{
top->Iin = InstructionMemory[(top->Iaddr)/4];
}
else
{
top->Iin = InstructionMemory[(top->Iaddr-4194608)/4];
}
//instruction split
if(main_time%2)
printf("IMAddr:%d IM:%d \n***************\n",top->Iaddr,InstructionMemory[(top->Iaddr)/4]);//-4194608)/4]);
//evaluate instruction call and increment time counter
top->eval();
main_time++;
//exit loop
if(main_time>=2)
{
return 0;
}
top->Iin = 3690987776;
//SYSCALL
if ( top->Iin == 3690987584 )//exit 1
{
cout << "Exit" << endl;
return 0;
}
else if ( top->Iin == 3690987776 )//open 4
{
cout << endl << endl << "Open File" << endl << endl;
string filename;
filename = "DATA.txt";
//fill filename with characters from memory
//FDT_filename(top->a0) is the string start pointer
FDT_filename.push_back(filename);//add new filename to newest location
FDT_state.push_back(1);//add new open indicator to newest location
top->v0 = FileDescriptorIndex;//place file descriptor into register
FileDescriptorIndex++;//ready the next file descriptor
//printf("Filename:%d FileDescriptorIndex:%d",FDT_filename.at3(FileDescriptorIndex),FileDescriptorIndex);
}
else if ( top->Iin == 3690987648 )//read 2
{
cout << "Read" << endl;
int max_char_count = top->a2;
int char_CTR = 0;
//create file object and open filename
//read chars from file
//place in
//FILE *f = fopen(filename,"rb");
//scanf("%s %top->a2",&FDT_filename(top->a0) >> top->a1;
//top->v0 = char_CTR;
}
else if ( top->Iin == 3690987712 )//write 3
{
cout << "Write" << endl;
int max_char_count = top->a2;
int char_CTR = 0;
//f fopen(FDT_filename(top->a0));
}
else if ( top->Iin == 3690987840 )//close 5
{
cout << "Close File" << endl;
//FDT_state(top->v0)=0;
}
else if ( top->Iin == 3690987904 )//time 6
{
cout << "Time:" << main_time << endl;
top->a0 = main_time;
top->a1 = main_time;
}
}
}