Well, basically that's what I need :
I've got an extern(al) char * variable
I want to assign the value of a D string
Code :
import std.stdio;
import std.string;
import core.stdc.stdlib;
extern (C) int yyparse();
extern (C) extern __gshared FILE* yyin;
extern (C) extern __gshared char* yyfilename;
void main(string[] args)
{
string filename = args[1];
auto file = File(filename, "r");
yyfilename = toStringz(filename);
yyin = file.getFP();
yyparse();
}
However, the toStringz function returns this error :
main.d(15): Error: cannot implicitly convert expression (toStringz(filename)) of type immutable(char)* to char*
Any idea what's going wrong?
The problem is that yyfilename, and the return value of toStringz when it is passed a string, have different const qualifiers. filename is immutable (D string is an alias to immutable(char)[]), however yyfilename does not have any const qualifier, and is thus mutable.
You have two options:
If you know that yyfilename will not bemodified elsewhere in your program, you should declare it as const(char)* instead of char*.
Otherwise, you should create a copy of filename when converting it: toUTFz!(char*)(filename).
You can use:
import std.utf;
void main()
{
string filename;
char* yyfilename;
yyfilename = toUTFz!(char*)(filename);
// yyfilename = filename.toUTFz!(char*); // or with UFCS syntax
}
Related
To reduce the usage of SRAM on my Arduino I'd like to print some text via the F() makro:
void setup() {
char text[] = "i am just text";
if(Serial) {
Serial.println(F(text));
}
}
But this throws the following error
C:\Temp\Software\arduino-1.8.10\hardware\arduino\avr\cores\arduino/WString.h:38:74:
error: initializer fails to determine size of '__c'
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper*>(PSTR(string_literal)))
C:\Temp\Software\arduino-1.8.10\hardware\arduino\avr\cores\arduino/WString.h:38:74:
error: array must be initialized with a brace-enclosed initializer
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper*>(PSTR(string_literal)))
But I don't really understand how to fix this. Could someone please help me to Serial.println() the text variable via F()?
In your example, text is a mutable char[]. Moving that to flash would be problematic. Changing the mutable in runtime, text[0] = 'I';, would not work as promised. Use the macro with a const char* instead - and do it around the string literal you want flashed.
Try:
auto text = F("i am just text");
// or: auto text = FPSTR("i am just text");
// or: static const char text[] PROGMEM = "i am just a text";
Serial.println(text);
When passing it to a function, you could add an overload for const __FlashStringHelper* (like Print and Println has):
void debug(const __FlashStringHelper *txt) {
Serial.println(txt);
}
...
debug(text);
Disclamer: Untested
I'm trying to assign a value to a char** variable. In my foo.h I've defined a couple of variables such as
#define APIOCTET int
#define APILONG long
#define APICHAR char
#define APISTRING char*
Now in my foo.cpp I'm tryng to use a method where
APILONG apiInitialize(APISTRING filePath, APISTRING* outputString)
{
//open text file to where output will be printed
//do other stuff, etc..
//return result;
}
I'd like to assign a value to my APISTRING* outputString but I just can't figure out how to do so, I've tried many things which are basically a variation of the following code
APISTRING error = "error";
APISTRING other = "string";
APISTRING charArr[] = { error, other, error };
APISTRING *charArr2[] = { charArr };
errorString = *charArr2;
Also im not 100% clear on what exactly is APISTRING* outputString. When I try to compile it gives me an error message where it mentions it's a char**. Is it a 2D array?.. A pointer to an array of chars?.. But most importantly, how would I assign a value for this variable? Thanks in advance.
The APISTRING* is a pointer to a pointer to char. It holds an address which holds the address of the first character of the string in memory.
See this question for more info on double pointers in C/C++.
To assign to the string you would need to do *outputString = "string"
APISTRING* outputString will be pre-processed and replcaed at compile-time as char** outputstring. Hence, outputString will be double pointer hence, you need to do it like this (below code). I combined both .h and cpp together for simplicity.
#include<iostream>
using namespace std;
#define APIOCTET int
#define APILONG long
#define APICHAR char
#define APISTRING char*
APILONG apiInitialize(APISTRING filePath, APISTRING* outputString)
{
APISTRING getIt = *outputString;
cout<<" "<<getIt<<endl;
}
int main()
{
APISTRING str = "hello";
APISTRING* outputString = &str;
APILONG val = apiInitialize("world", outputString );
system("PAUSE");
return 0;
}
I would recommend to use std::string, it'll be easy to tweak with certain behaviors. Hope this helps.
I'm trying to use ToCString in a NodeJS addon.
String::Utf8Value foo_utf8(args[0]->ToString());
const char *foo = ToCString(foo_utf8);
I can't find it's header, and if I manually prototype it as:
const char* ToCString(const v8::String::Utf8Value& value);
then I get a runtime error of:
node: symbol lookup error: /home/chris/Dropbox/cbackend/build/Release/cbackend.node:
undefined symbol: _Z9ToCStringRKN2v86String9Utf8ValueE
How can I convert a V8 String argument to a null-terminated 8 bit C string?
I found a workaround, as the ToCString function (wherever it lives) is trivial. Just add:
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
Going by the docs, v8 has operators for cstr conversion:
Local<Value> value = get_value(); // nan† thing, you can ignore this
v8::String::Utf8Value string(value);
char* str = *string; // defined as: char * operator* ()
const char* const_str = *string; // defined as: const char * operator* () const
This applies to both njs v0.10 and v0.11.
† https://github.com/rvagg/nan
In C++ I wanted to define a constant that I can use in another function, A short answer on how to do this will be fine..
Lets say at the beginning of my code I want to define this constant:
//After #includes
bool OS = 1; //1 = linux
if (OS) {
const ??? = "clear";
} else {
const ??? = "cls";
}
I don't know what type to use to define the "clear" string... I'm so confused.
Later on I want to use it within a function:
int foo() {
system(::cls); //:: for global
return 0;
}
How would I define the string up top, and use the string down below? I heard char only had one character and things... I'm not sure how to use , since it says it's converting string into const char or something.
char* isn't quite a char. char* is basically a string (it's what strings were before C++ came along).
For illustration:
int array[N]; // An array of N ints.
char str[N]; // An array of N chars, which is also (loosely) called a string.
char[] degrades to char*, so you'll often see functions take a char*.
To convert std::string to const char*, you can simply call:
std::string s;
s.c_str()
In this case, it's common to use the preprocessor to define your OS. This way you can use the compiler to do the platform specific stuff:
#ifdef OS_LINUX
const char cls[] = "clear";
#elif OS_WIN
const char cls[] = "cls";
#endif
One thing you may want to consider is making it a function. This avoids nasty dependencies of global construction order.
string GetClearCommand() {
if (OS == "LINUX") {
return "clear";
} else if (OS == "WIN") {
return "cls";
}
FAIL("No OS specified?");
return "";
}
What it looks like you're trying to do is this:
#include <iostream>
using namespace std;
#ifdef LINUX
const char cls[] = "LINUX_CLEAR";
#elif WIN
const char cls[] = "WIN_CLEAR";
#else
const char cls[] = "OTHER_CLEAR";
#endif
void fake_system(const char* arg) {
std::cout << "fake_system: " << arg << std::endl;
}
int main(int argc, char** argv) {
fake_system(cls);
return 0;
}
// Then build the program passing your OS parameter.
$ g++ -DLINUX clear.cc -o clear
$ ./clear
fake_system: LINUX_CLEAR
Here's the problem, you're suffering from going out of scope with the variables. If I declare something within brackets, it only exists within the brackets.
if( foo ){
const char* blah = "blah";
}
Once we leave the if statement, the variable blah disappears. You'll need to instantiate it non-locally to whatever brackets you write. Hence:
void Bar(){
const char* blah = "blah";
if( foo ){
//blah exists within here
}
}
However, blah will not exist outside of Bar. Get it?
Yet another option is to create a class with a bunch of static methods. Create a new method for each command. Something like:
// in sys-commands.h
class SystemCommands {
public:
static char const* clear();
static char const* remove();
};
This gives you a few nice options for the implementation. The nicest one is to have a separate implementation file for each platform that you select during compile time.
// in sys-commands-win32.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "cls"; }
char const* SystemCommands::remove() { return "erase /f/q"; }
// in sys-commands-macosx.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "/usr/bin/clear"; }
char const* SystemCommands::remove() { return "/bin/rm -fr"; }
Which file gets compiled will determine which command set will be used. Your application code will look like:
#include <cstdlib>
#include "sys-commands.h"
int main() {
std::system(SystemCommands::clear());
return 0;
}
Edit: I forgot to mention that I prefer static functions to global constants for a bunch of reasons. If nothing else, you can make them non-constant without changing their types - in other words, if you ever have to select the command set based on runtime settings, the user code does not have to change or even be aware that such a change occurred.
You can use a common header file and link to different modules depending on the systen:
// systemconstants.hpp
#ifndef SYSTEM_CONSTANTS_HPP_INCLUDED
#define SYSTEM_CONSTANTS_HPP_INCLUDED
namespace constants {
extern const char cls[]; // declaration of cls with incomplete type
}
#endif
In case of Linux, just compile and link to this one:
// linux/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "clear";
}
In case of Windows, just compile and link to this one:
// windows/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "cls";
}
System-specific translation units could be placed in specific subdirectories (linux/, windows/, etc) of which one could be automatically selected during the build process. This extends to many other things, not just string constants.
I'm learning cpp and In my last assignment I am rewriting the std::string class.
so here is an outline of my code:
string class:
class String {
public:
String(const char* sInput) {
string = const_cast<char*> (sInput);
}
const String operator+(const char* str) {
//snip
print();
}
void print() {
cout<<string;
}
int search(char* str) {
}
private:
char* string;
int len;
};
Oh and I have to say I tried to declare the method as String* operator+(const char* str) and as const String& operator+(const char* str) with no change.
And here is how I run it:
int main(int argc, char* argv[]) {
String* testing = new String("Hello, "); //works
testing->print();//works
/*String* a = */testing+"World!";//Error here.
return 0;
}
The full error goes like such:
foobar.cc:13: error: invalid operands
of types ‘String*’ and ‘const char
[7]’ to binary ‘operator+’
I looked up on Google and in the book I am learning from with no success.
any one with suggestions? (I am pretty sure I am doing something foolish you will have to forgive me I am originally a PHP programmer) can any one point me to what am I missing?
You probably don't want to use a pointer to your String class. Try this code:
int main(int argc, char* argv[]) {
String testing = String("Hello, "); //works
testing.print();//works
String a = testing+"World!";
return 0;
}
When defining new operators for C++ types, you generally will work with the actual type directly, and not a pointer to your type. C++ objects allocated like the above (as String testing) are allocated on the stack (lives until the end of the "scope" or function) instead of the heap (lives until the end of your program).
If you really want to use pointers to your type, you would modify the last line like this:
String *a = new String(*testing + "World!");
However, following the example of std::string this is not how you would normally want to use such a string class.
Your operator+ is defined for String and const* char, not for String*. You should dereference testing before adding it, i.e.:
String a = (*testing) + "World";
Though in this case I don't see the point in making testing a pointer in the fist place.
Edit: Creating a string without pointers would look like this:
String testing = "Hello, ";
or
String testing("Hello, ");
(both are equivalent).