I have a const char** called glfwNames which holds the C version of a string array of the required GLFW library extensions. Would it be possible to loop through either the const char* (string), or the individual characters of the string separated by '\0'?
const char** glfwNames = glfwGetRequiredInstanceExtensions(&glfwCount)
for (const char** name = glfwNames; *name; ++name)
{
slog("GLFW Extensions to use: %s", *name);
}
This is what I've attempted from one of the answers, and the return value of
glfwGetRequiredInstanceExtensions
is an array of extension names, required by GLFW http://www.glfw.org/docs/latest/group__vulkan.html#ga1abcbe61033958f22f63ef82008874b1
If glfwNames is nullptr-terminated:
#include <cstdio>
int main()
{
char const *glfwNames[] = { "foo", "bar", "baz", nullptr };
for (char const **p = glfwNames; *p; ++p)
std::puts(*p);
}
If you *know* the number of strings:
std::uint32_t glfwCount;
const char** glfwNames = glfwGetRequiredInstanceExtensions(&glfwCount)
for (std::uint32_t i{}; i < glfwCount; ++i)
{
slog("GLFW Extensions to use: %s", glfwNames[i]);
}
To also loop through the individual chars:
for (std::uint32_t i{}; i < glfwCount; ++i)
{
for(char const *p{ glfwNames[i] }; *p; ++p)
std::putchar(*p);
}
A common pattern that I use to loop through the arguments to main is via std::for_each:
#include <algorithm>
int main(int argc, char* argv[]) {
std::for_each( argv + 1, argv + argc, handler );
}
where handler is any function taking a const char*, const std::string&, or std::string_view (I use the later).
Would a similar approach work for your problem? Notice that this approach requires you to know the length of your array of strings.
As a side note, it is important to know that the return argument of std::for_each is the function provided (handler in this case). That enables the suggested pattern to make a last call once the input is known to have been exhausted:
#include <algorithm>
int main(int argc, char* argv[]) {
std::for_each( argv + 1, argv + argc, handler )("Argument To Last Call");
}
This can be used to implement state machines that receive the termination trigger at the end.
Related
I'd like to be able to save argv into a struct so that it can be passed to functions like so:
struct Parameters {
int argc;
char * argv[];
};
void Start(
Parameters P
) {
};
int main (
int argc,
char * argv []
) {
Parameters P;
P.argc = argc;
P.argv = & argv;
return 0;
}
But with:
clang++ -std=c++2a -stdlib=libc++ -rtlib=compiler-rt -Ofast Start.cpp -o Start && ./Start;
I'm getting this error:
Start.cpp:21:9: error: array type 'char *[]' is not assignable
Is there a way of saving argv to a variable? Any help would be very much appreciated.
A simple way is to convert it to a vector of strings:
int main(int argc, char* argv[])
{
// Note: use argv + 1 to skip the application name in args.
// If you want to include the application name then don't use
// the +1
std::vector<std::string> args(argv + 1, argv + argc);
// Now this can be passed to functions easily.
// args.size() == number of arguments.
// args[x] == the string for argument x
}
You can simply change to:
struct Parameters
{
int argc;
char ** argv;
};
Your argv array of pointers to char will decay to a pointer to pointer to char.
Then, your main becomes simpler, with:
P.argv = argv;
Following this post, where I have found a temporary workaround for my other problem, I want to know if I can replace the int argc, char** argv with a std::vector<std::string> variable/object.
Consider the imaginary code:
#include <iostream>
#include <CloseLibrary>
void someFunction(int argc, char** argv){
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
int myFunc(int argc, char** argv){
someFunction(argc, argv);
return 0;
}
where the CloseLibrary is a closed library that I don't have access to the source code, and the someFunction function from that library demands the int argc, char** argv command line arguments. But for some reason I can't have double pointers char** in my code.
Here in this post something like what I need is proposed, but I don't know how to use that. Can I write the code this way:
#include <iostream>
#include <CloseLibrary>
#include <vector>
void someFunction(int argc, char** argv){
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
int myFunc("args", [](std::vector<std::string> args){
std::vector<char *> cstrs;
cstrs.reserve(args.size());
for (auto &s : args) cstrs.push_back(const_cast<char *>(s.c_str()));
someFunction(cstrs.size(), cstrs.data());
return 0;
}
Or maybe there is a more canonical way to do this? I would appreciate it if you could help me find the correct way to do this and understand the solution. Thanks for your help in advance.
P.S.1. The char* argv[] method is ok in the body of the function but not ok in the inputs. I don't know why pybind11 does this!
P.S.2. Here on pybind11 gitter, this was suggested:
void run(const std::vector<std::string>& args) {
for(auto&& e : args) std::cout << e << '\n';
}
P.S.3. Also suggested on pybind11 Gitter:
char** argv = new char*[vec.size()]; // just like malloc(sizeof(char*)*vec.size());
for (int i = 0; i < vec.size(), i++) {
argv[i] = new char[vec[i].size()];
memcpy(argv[i], vec[i].data(), vec[i].size()); // or strcpy
}
You could use the constructor which initializes the vector from a given range, with the argv parameter acts as the starting iterator and argv+argc acting as the ending iterator.
For example, I usually start my main function with:
int main( int argc, char* argv[] )
{
std::vector< std::string > args( argv, argv + argc );
for ( auto s : args )
{
std::cout << s << std::endl;
}
}
Note that this will also capture the first argument (argv[0]) which usually (but not necessarily) hold the name of the application when it is started.
In your case, you would like to do the reverse, build up a contiguous array of char* from a std::vector< std::string >. I would do something like:
std::vector< char* > rargs( args.size(), 0 ); // Initialize N nullptrs.
for ( int i=0; i<args.size(); ++i )
{
std::strcpy( rargs[i], args[i].c_str() ); // One-by-one strcpy them
}
And then you can pass them into a function accepting an argc, argv as
someFunction( rargs.size(), rargs.data() );
For what it's worth ... Taking it completely back to your original problem of not being able to use char** with pybind11, a full working example, scavenged from the pieces you posted is below. Yes, it's not pretty, but working with pointers never is.
#include <pybind11/pybind11.h>
#include <iostream>
#if PY_VERSION_HEX < 0x03000000
#define MyPyText_AsString PyString_AsString
#else
#define MyPyText_AsString PyUnicode_AsUTF8
#endif
namespace py = pybind11;
void closed_func(int argc, char** argv){
for (int i = 0; i < argc; ++i) {
std::cout << "FROM C++: " << argv[i] << std::endl;
}
}
void closed_func_wrap(py::object pyargv11) {
int argc = 0;
std::unique_ptr<char*[]> argv;
// convert input list to C/C++ argc/argv
PyObject* pyargv = pyargv11.ptr();
if (PySequence_Check(pyargv)) {
Py_ssize_t sz = PySequence_Size(pyargv);
argc = (int)sz;
argv = std::unique_ptr<char*[]>{new char*[sz]};
for (Py_ssize_t i = 0; i < sz; ++i) {
PyObject* item = PySequence_GetItem(pyargv, i);
argv[i] = (char*)MyPyText_AsString(item);
Py_DECREF(item);
if (!argv[i] || PyErr_Occurred()) {
argv = nullptr;
break;
}
}
}
// bail if failed to convert
if (!argv) {
std::cerr << "argument is not a sequence of strings" << std::endl;
return;
}
// call the closed function with the proper types
closed_func(argc, argv.get());
}
PYBIND11_MODULE(HelloEposCmd, m)
{
m.def("run", &closed_func_wrap, "runs the HelloEposCmd");
}
Which after compiling can be used as expected:
$ python - a b c d=13
>>> import HelloEposCmd
>>> import sys
>>> HelloEposCmd.run(sys.argv)
FROM C++: -
FROM C++: a
FROM C++: b
FROM C++: c
FROM C++: d=13
>>>
In a C++ application, the arguments are all stored in a char* array, like so:
int main(int argc, char* argv[])
{
...
}
However, a lot of people prefer the convenience of string manipulation, but it would be a hastle to have to convert every char* into a std::string every time. So my question is, how do convert a char*[] into a std::string[], so that you don't have to convert them all individually as you progress in your program?
If you accept std::vector, you can use its range constructor.
std::vector<std::string> args(argv, argv + argc);
You can loop through the arguments.
int main(int argc, char* argv[]) {
std::string *s = new std::string[argc];
for (int i = 0; i < argc; ++i)
s[i] = argv[i];
}
I am writing a command shell in C++ using the POSIX api, and have hit a snag. I am executing via execvp(3), so I somehow need to turn the std::string that contains the command into a suitable array of char* consts*'s that can be passed to:
int execvp(const char *file, char *const argv[]);
I have been racking my brain for hours but I can't think of any realistic or sane way to do this. Any help or insight on how I can achieve this conversion would be greatly appreciated. Thank you and have a good day!
edit:
As per request of Chnossos, here is an example:
const char *args[] = {"echo", "Hello,", "world!"};
execvp(args[0], args);
Assuming you have a string that contains more than "one argument", you will first have to split the string (using a std::vector<std::string> would work to store the separate strings), then for each element in the vector, store the .c_str() of that string into a const char args[MAXARGS] [or a std::vector<const char*> args; and use args.data() if you don't mind using C++11]. Do not forget to store a 0 or nullptr in the last element.
It is critical if you use c_str that the string you are basing that of is not a temporary: const char* x = str.substr(11, 33).c_str(); will not give you the thing you want, because at the end of that line, the temporary string is destroyed, and its storage freed.
If you have only one actual argument,
const char* args[2] = { str.c_str(), 0 };
would work.
Examplary approach:
#include <string>
#include <vector>
#include <cstring>
using namespace std;
int execvp(const char *file, char *const argv[]) {
//doing sth
}
int main() {
string s = "echo Hello world!";
char* cs = strdup(s.c_str());
char* lastbeg = cs;
vector<char *> collection;
for (char *itcs = cs; *itcs; itcs++) {
if (*itcs == ' ') {
*itcs = 0;
collection.push_back(lastbeg);
lastbeg = itcs + 1;
}
}
collection.push_back(lastbeg);
for (auto x: collection) {
printf("%s\n", x);
}
execvp("abc.txt", &collection[0]);
}
Notice that the memory for the cs isn't freed here... in your application you would need to take care of that...
The number of elements in array can be simply extracted from collection.size()
I use this:
command_line.hpp:
#pragma once
#include <vector>
#include <string>
namespace wpsc { namespace unittest { namespace mock {
class command_line final
{
public:
explicit command_line(std::vector<std::string> args = {});
explicit command_line(int argc, char const * const * const argv);
int argc() const;
/// #remark altering memory returned by this function results in UB
char** argv() const;
std::string string() const;
private:
std::vector<std::string> args_;
mutable std::vector<char*> c_args_;
};
}}} // wpsc::unittest::mock
command_line.cpp:
#include <wpsc/unittest/mock/command_line.hpp>
#include <algorithm>
#include <sstream>
namespace wpsc { namespace unittest { namespace mock {
command_line::command_line(std::vector<std::string> args)
: args_( std::move(args) ), c_args_( )
{
}
command_line::command_line(int argc, char const * const * const argv)
: command_line{ std::vector<std::string>{ argv, argv + argc } }
{
}
int command_line::argc() const
{
return static_cast<int>(args_.size());
}
char ** command_line::argv() const
{
if(args_.empty())
return nullptr;
if(c_args_.size() != args_.size() + 1)
{
c_args_.clear();
using namespace std;
transform(begin(args_), end(args_), back_inserter(c_args_),
[](const std::string& s) { return const_cast<char*>(s.c_str()); }
);
c_args_.push_back(nullptr);
}
return c_args_.data();
}
std::string command_line::string() const
{
using namespace std;
ostringstream buffer;
copy(begin(args_), end(args_), ostream_iterator<std::string>{ buffer, " " });
return buffer.str();
}
}}} // wpsc::unittest::mock
Client code:
int main(int argc, char** argv)
{
wpsc::unittest::mock::command_line cmd1{ argc, argv };
// wpsc::unittest::mock::command_line cmd2{ {"app.exe" "-h"} };
some_app_controller c;
return c.run(cmd1.argc(), cmd1.argv());
}
If the parsing can actually be really complicated, I'd go with something like that:
std::string cmd = "some really complicated command here";
char * const args[] =
{
"sh",
"-c",
cmd.c_str(),
(char *) NULL
};
execvp(args[0], args);
So the problem is the splitting of the line into individual arguments, and filling the argument vector with the respective pointers?
Assuming you want to split at the whitespace in the line, you replace whitespace in the string with null-bytes (in-place). You can then fill the argument vector with pointers into the string.
You will have to write a single loop to go through the string.
You need to decide what the rules will be for your shell and implement them. That's a significant fraction of the work of making a shell.
You need to write this code, and it's not simple. In a typical shell, echo "Hello world!" has to become { echo, Hello world! }, while echo \"Hello world!\" has to become { echo, "Hello world!" }. And so on.
What will " do in your shell? What will ' do? You need to make these decision before you code this part.
The parameter to main char* argv[] decays to char**, which is unfortunate, because it cannot be used with std::begin which only accepts arrays. The only workaround I see is to use a variable length array which is undesirable.
#include <iostream>
int main(int argc, char* argv[])
{
char* _argv[argc];
for (int i = 0; i < argc; ++i)
_argv[i] = argv[i];
for (arg : _argv)
{
std::cout << arg << " ";
}
return 0;
}
Desirably I want something like: char* _argv[] = { ... };
That is not possible, since the signature of main is fixed. You can copy the elements to a vector using:
std::vector<std::string> args {argv, argv + argc};
Then you can use std::begin on args
You can define a simple class wrapper to give you begin() and end().
struct Args {
int argc_;
char **argv_;
Args (int argc, char *argv[]) : argc_(argc), argv_(argv) {}
char ** begin () { return argv_; }
char ** end () { return argv_ + argc_; }
};
int main(int argc, char *argv[]) {
for (auto s : Args(argc, argv)) {
std::cout << s << '\n';
}
return 0;
}
The only workaround I see is to use a variable length array which is
undesirable.
The only workaround for what exactly? There is no problem. If you actually need an array of strings, use a vector as shown in TNAs answer; I doubt you need to modify the parameters though.
If you just need to iterate through it, there is no need to copy all the pointers.
for (auto str : boost::make_iterator_range(argv, argv + argc))
std::cout << str;
Or
for (auto ptr = argv; ptr != argv + argc; ++ptr)
std::cout << *ptr << '\n';
The parameter to main char* argv[] decays to char**, which is
unfortunate, because it cannot be used with std::begin which only
accepts arrays.
There is no other way. The amount of command line parameters is not known at compile time, and this method of passing them (instead of using two pointers-to-pointers) is historically motivated.