Is there a way to include an entire text file as a string in a C program at compile-time?
something like:
file.txt:
This is
a little
text file
main.c:
#include <stdio.h>
int main(void) {
#blackmagicinclude("file.txt", content)
/*
equiv: char[] content = "This is\na little\ntext file";
*/
printf("%s", content);
}
obtaining a little program that prints on stdout "This is
a little
text file"
At the moment I used an hackish python script, but it's butt-ugly and limited to only one variable name, can you tell me another way to do it?
I'd suggest using (unix util)xxd for this.
you can use it like so
$ echo hello world > a
$ xxd -i a
outputs:
unsigned char a[] = {
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;
The question was about C but in case someone tries to do it with C++11 then it can be done with only little changes to the included text file thanks to the new raw string literals:
In C++ do this:
const char *s =
#include "test.txt"
;
In the text file do this:
R"(Line 1
Line 2
Line 3
Line 4
Line 5
Line 6)"
So there must only be a prefix at the top of the file and a suffix at the end of it. Between it you can do what you want, no special escaping is necessary as long as you don't need the character sequence )". But even this can work if you specify your own custom delimiter:
R"=====(Line 1
Line 2
Line 3
Now you can use "( and )" in the text file, too.
Line 5
Line 6)====="
I like kayahr's answer. If you don't want to touch the input files however, and if you are using CMake, you can add the delimeter character sequences on the file. The following CMake code, for instance, copies the input files and wraps their content accordingly:
function(make_includable input_file output_file)
file(READ ${input_file} content)
set(delim "for_c++_include")
set(content "R\"${delim}(\n${content})${delim}\"")
file(WRITE ${output_file} "${content}")
endfunction(make_includable)
# Use like
make_includable(external/shaders/cool.frag generated/cool.frag)
Then include in c++ like this:
constexpr char *test =
#include "generated/cool.frag"
;
You have two possibilities:
Make use of compiler/linker extensions to convert a file into a binary file, with proper symbols pointing to the begin and end of the binary data. See this answer: Include binary file with GNU ld linker script.
Convert your file into a sequence of character constants that can initialize an array. Note you can't just do "" and span multiple lines. You would need a line continuation character (\), escape " characters and others to make that work. Easier to just write a little program to convert the bytes into a sequence like '\xFF', '\xAB', ...., '\0' (or use the unix tool xxd described by another answer, if you have it available!):
Code:
#include <stdio.h>
int main() {
int c;
while((c = fgetc(stdin)) != EOF) {
printf("'\\x%X',", (unsigned)c);
}
printf("'\\0'"); // put terminating zero
}
(not tested). Then do:
char my_file[] = {
#include "data.h"
};
Where data.h is generated by
cat file.bin | ./bin2c > data.h
You can do this using objcopy:
objcopy --input binary --output elf64-x86-64 myfile.txt myfile.o
Now you have an object file you can link into your executable which contains symbols for the beginning, end, and size of the content from myfile.txt.
ok, inspired by Daemin's post i tested the following simple example :
a.data:
"this is test\n file\n"
test.c:
int main(void)
{
char *test =
#include "a.data"
;
return 0;
}
gcc -E test.c output:
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.c"
int main(void)
{
char *test =
# 1 "a.data" 1
"this is test\n file\n"
# 6 "test.c" 2
;
return 0;
}
So it's working but require data surrounded with quotation marks.
If you're willing to resort to some dirty tricks you can get creative with raw string literals and #include for certain types of files.
For example, say I want to include some SQL scripts for SQLite in my project and I want to get syntax highlighting but don't want any special build infrastructure. I can have this file test.sql which is valid SQL for SQLite where -- starts a comment:
--x, R"(--
SELECT * from TestTable
WHERE field = 5
--)"
And then in my C++ code I can have:
int main()
{
auto x = 0;
const char* mysql = (
#include "test.sql"
);
cout << mysql << endl;
}
The output is:
--
SELECT * from TestTable
WHERE field = 5
--
Or to include some Python code from a file test.py which is a valid Python script (because # starts a comment in Python and pass is a no-op):
#define pass R"(
pass
def myfunc():
print("Some Python code")
myfunc()
#undef pass
#define pass )"
pass
And then in the C++ code:
int main()
{
const char* mypython = (
#include "test.py"
);
cout << mypython << endl;
}
Which will output:
pass
def myfunc():
print("Some Python code")
myfunc()
#undef pass
#define pass
It should be possible to play similar tricks for various other types of code you might want to include as a string. Whether or not it is a good idea I'm not sure. It's kind of a neat hack but probably not something you'd want in real production code. Might be ok for a weekend hack project though.
You need my xtr utility but you can do it with a bash script. This is a script I call bin2inc. The first parameter is the name of the resulting char[] variable. The second parameter is the name of the file. The output is C include file with the file content encoded (in lowercase hex) as the variable name given. The char array is zero terminated, and the length of the data is stored in $variableName_length
#!/bin/bash
fileSize ()
{
[ -e "$1" ] && {
set -- `ls -l "$1"`;
echo $5;
}
}
echo unsigned char $1'[] = {'
./xtr -fhex -p 0x -s ', ' < "$2";
echo '0x00'
echo '};';
echo '';
echo unsigned long int ${1}_length = $(fileSize "$2")';'
YOU CAN GET XTR HERE xtr (character eXTRapolator) is GPLV3
Why not link the text into the program and use it as a global variable! Here is an example. I'm considering using this to include Open GL shader files within an executable since GL shaders need to be compiled for the GPU at runtime.
I reimplemented xxd in python3, fixing all of xxd's annoyances:
Const correctness
string length datatype: int → size_t
Null termination (in case you might want that)
C string compatible: Drop unsigned on the array.
Smaller, readable output, as you would have written it: Printable ascii is output as-is; other bytes are hex-encoded.
Here is the script, filtered by itself, so you can see what it does:
pyxxd.c
#include <stddef.h>
extern const char pyxxd[];
extern const size_t pyxxd_len;
const char pyxxd[] =
"#!/usr/bin/env python3\n"
"\n"
"import sys\n"
"import re\n"
"\n"
"def is_printable_ascii(byte):\n"
" return byte >= ord(' ') and byte <= ord('~')\n"
"\n"
"def needs_escaping(byte):\n"
" return byte == ord('\\\"') or byte == ord('\\\\')\n"
"\n"
"def stringify_nibble(nibble):\n"
" if nibble < 10:\n"
" return chr(nibble + ord('0'))\n"
" return chr(nibble - 10 + ord('a'))\n"
"\n"
"def write_byte(of, byte):\n"
" if is_printable_ascii(byte):\n"
" if needs_escaping(byte):\n"
" of.write('\\\\')\n"
" of.write(chr(byte))\n"
" elif byte == ord('\\n'):\n"
" of.write('\\\\n\"\\n\"')\n"
" else:\n"
" of.write('\\\\x')\n"
" of.write(stringify_nibble(byte >> 4))\n"
" of.write(stringify_nibble(byte & 0xf))\n"
"\n"
"def mk_valid_identifier(s):\n"
" s = re.sub('^[^_a-z]', '_', s)\n"
" s = re.sub('[^_a-z0-9]', '_', s)\n"
" return s\n"
"\n"
"def main():\n"
" # `xxd -i` compatibility\n"
" if len(sys.argv) != 4 or sys.argv[1] != \"-i\":\n"
" print(\"Usage: xxd -i infile outfile\")\n"
" exit(2)\n"
"\n"
" with open(sys.argv[2], \"rb\") as infile:\n"
" with open(sys.argv[3], \"w\") as outfile:\n"
"\n"
" identifier = mk_valid_identifier(sys.argv[2]);\n"
" outfile.write('#include <stddef.h>\\n\\n');\n"
" outfile.write('extern const char {}[];\\n'.format(identifier));\n"
" outfile.write('extern const size_t {}_len;\\n\\n'.format(identifier));\n"
" outfile.write('const char {}[] =\\n\"'.format(identifier));\n"
"\n"
" while True:\n"
" byte = infile.read(1)\n"
" if byte == b\"\":\n"
" break\n"
" write_byte(outfile, ord(byte))\n"
"\n"
" outfile.write('\";\\n\\n');\n"
" outfile.write('const size_t {}_len = sizeof({}) - 1;\\n'.format(identifier, identifier));\n"
"\n"
"if __name__ == '__main__':\n"
" main()\n"
"";
const size_t pyxxd_len = sizeof(pyxxd) - 1;
Usage (this extracts the script):
#include <stdio.h>
extern const char pyxxd[];
extern const size_t pyxxd_len;
int main()
{
fwrite(pyxxd, 1, pyxxd_len, stdout);
}
Here's a hack I use for Visual C++. I add the following Pre-Build Event (where file.txt is the input and file_txt.h is the output):
#(
echo const char text[] = R"***(
type file.txt
echo ^^^)***";
) > file_txt.h
I then include file_txt.h where I need it.
This isn't perfect, as it adds \n at the start and \n^ at the end, but that's not a problem to handle and I like the simplicity of this solution. If anyone can refine is to get rid of the extra chars, that would be nice.
You can use assembly for this:
asm("fileData: .incbin \"filename.ext\"");
asm("fileDataEnd: db 0x00");
extern char fileData[];
extern char fileDataEnd[];
const int fileDataSize = fileDataEnd - fileData + 1;
Even if it can be done at compile time (I don't think it can in general), the text would likely be the preprocessed header rather than the files contents verbatim. I expect you'll have to load the text from the file at runtime or do a nasty cut-n-paste job.
Hasturkun's answer using the xxd -i option is excellent. If you want to incorporate the conversion process (text -> hex include file) directly into your build the hexdump.c tool/library recently added a capability similar to xxd's -i option (it doesn't give you the full header - you need to provide the char array definition - but that has the advantage of letting you pick the name of the char array):
http://25thandclement.com/~william/projects/hexdump.c.html
It's license is a lot more "standard" than xxd and is very liberal - an example of using it to embed an init file in a program can be seen in the CMakeLists.txt and scheme.c files here:
https://github.com/starseeker/tinyscheme-cmake
There are pros and cons both to including generated files in source trees and bundling utilities - how to handle it will depend on the specific goals and needs of your project. hexdump.c opens up the bundling option for this application.
I think it is not possible with the compiler and preprocessor alone. gcc allows this:
#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)
printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
STRGF(
# define hostname my_dear_hostname
hostname
)
"\n" );
But unfortunately not this:
#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)
printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
STRGF(
# include "/etc/hostname"
)
"\n" );
The error is:
/etc/hostname: In function ‘init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"
I had similar issues, and for small files the aforementioned solution of Johannes Schaub worked like a charm for me.
However, for files that are a bit larger, it ran into issues with the character array limit of the compiler. Therefore, I wrote a small encoder application that converts file content into a 2D character array of equally sized chunks (and possibly padding zeros). It produces output textfiles with 2D array data like this:
const char main_js_file_data[8][4]= {
{'\x69','\x73','\x20','\0'},
{'\x69','\x73','\x20','\0'},
{'\x61','\x20','\x74','\0'},
{'\x65','\x73','\x74','\0'},
{'\x20','\x66','\x6f','\0'},
{'\x72','\x20','\x79','\0'},
{'\x6f','\x75','\xd','\0'},
{'\xa','\0','\0','\0'}};
where 4 is actually a variable MAX_CHARS_PER_ARRAY in the encoder. The file with the resulting C code, called, for example "main_js_file_data.h" can then easily be inlined into the C++ application, for example like this:
#include "main_js_file_data.h"
Here is the source code of the encoder:
#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>
#define MAX_CHARS_PER_ARRAY 2048
int main(int argc, char * argv[])
{
// three parameters: input filename, output filename, variable name
if (argc < 4)
{
return 1;
}
// buffer data, packaged into chunks
std::vector<char> bufferedData;
// open input file, in binary mode
{
std::ifstream fStr(argv[1], std::ios::binary);
if (!fStr.is_open())
{
return 1;
}
bufferedData.assign(std::istreambuf_iterator<char>(fStr),
std::istreambuf_iterator<char>() );
}
// write output text file, containing a variable declaration,
// which will be a fixed-size two-dimensional plain array
{
std::ofstream fStr(argv[2]);
if (!fStr.is_open())
{
return 1;
}
const std::size_t numChunks = std::size_t(std::ceil(double(bufferedData.size()) / (MAX_CHARS_PER_ARRAY - 1)));
fStr << "const char " << argv[3] << "[" << numChunks << "]" <<
"[" << MAX_CHARS_PER_ARRAY << "]= {" << std::endl;
std::size_t count = 0;
fStr << std::hex;
while (count < bufferedData.size())
{
std::size_t n = 0;
fStr << "{";
for (; n < MAX_CHARS_PER_ARRAY - 1 && count < bufferedData.size(); ++n)
{
fStr << "'\\x" << int(unsigned char(bufferedData[count++])) << "',";
}
// fill missing part to reach fixed chunk size with zero entries
for (std::size_t j = 0; j < (MAX_CHARS_PER_ARRAY - 1) - n; ++j)
{
fStr << "'\\0',";
}
fStr << "'\\0'}";
if (count < bufferedData.size())
{
fStr << ",\n";
}
}
fStr << "};\n";
}
return 0;
}
This problem was irritating me and xxd doesn't work for my use case because it made the variable called something like __home_myname_build_prog_cmakelists_src_autogen when I tried to script it in, so I made a utility to solve this exact problem:
https://github.com/Exaeta/brcc
It generates a source and header file and allows you to explicitly set the name of each variable so then you can use them via std::begin(arrayname) and std::end(arrayname).
I incorporated it into my cmake project like so:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binary_resources.hpp ${CMAKE_CURRENT_BINARY_DIR}/binary_resources.cpp
COMMAND brcc ${CMAKE_CURRENT_BINARY_DIR}/binary_resources RGAME_BINARY_RESOURCES_HH txt_vertex_shader ${CMAKE_CURRENT_BINARY_DIR}/src/vertex_shader1.glsl
DEPENDS src/vertex_shader1.glsl)
With small tweaks I suppose it could be made to work for C as well.
If you are using CMake, you probably may be interested in writing CMake preprocessing script like the following:
cmake/ConvertLayout.cmake
function(convert_layout file include_dir)
get_filename_component(name ${file} NAME_WE)
get_filename_component(directory ${file} DIRECTORY)
get_filename_component(directory ${directory} NAME)
string(TOUPPER ${name} NAME)
string(TOUPPER ${directory} DIRECTORY)
set(new_file ${include_dir}/${directory}/${name}.h)
if (${file} IS_NEWER_THAN ${new_file})
file(READ ${file} content)
string(REGEX REPLACE "\"" "\\\\\"" content "${content}")
string(REGEX REPLACE "[\r\n]" "\\\\n\"\\\\\n\"" content "${content}")
set(content "\"${content}\"")
set(content "#ifndef ${DIRECTORY}_${NAME}\n#define ${DIRECTORY}_${NAME} ${content} \n#endif")
message(STATUS "${content}")
file(WRITE ${new_file} "${content}")
message(STATUS "Generated layout include file ${new_file} from ${file}")
endif()
endfunction()
function(convert_layout_directory layout_dir include_dir)
file(GLOB layouts ${layout_dir}/*)
foreach(layout ${layouts})
convert_layout(${layout} ${include_dir})
endforeach()
endfunction()
your CMakeLists.txt
include(cmake/ConvertLayout.cmake)
convert_layout_directory(layout ${CMAKE_BINARY_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
somewhere in c++
#include "layout/menu.h"
Glib::ustring ui_info = LAYOUT_MENU;
I like #Martin R.'s answer because, as it says, it doesn't touch the input file and automates the process. To improve on this, I added the capability to automatically split up large files that exceed compiler limits. The output file is written as an array of smaller strings which can then be reassembled in code. The resulting script, based on #Martin R.'s version, and an example is included here:
https://github.com/skillcheck/cmaketools.git
The relevant CMake setup is:
make_includable( LargeFile.h
${CMAKE_CURRENT_BINARY_DIR}/generated/LargeFile.h
"c++-include" "L" LINE_COUNT FILE_SIZE
)
The source code is then:
static std::vector<std::wstring> const chunks = {
#include "generated/LargeFile.h"
};
std::string contents =
std::accumulate( chunks.begin(), chunks.end(), std::wstring() );
in x.h
"this is a "
"buncha text"
in main.c
#include <stdio.h>
int main(void)
{
char *textFileContents =
#include "x.h"
;
printf("%s\n", textFileContents);
return 0
}
ought to do the job.
What might work is if you do something like:
int main()
{
const char* text = "
#include "file.txt"
";
printf("%s", text);
return 0;
}
Of course you'll have to be careful with what is actually in the file, making sure there are no double quotes, that all appropriate characters are escaped, etc.
Therefore it might be easier if you just load the text from a file at runtime, or embed the text directly into the code.
If you still wanted the text in another file you could have it in there, but it would have to be represented there as a string. You would use the code as above but without the double quotes in it. For example:
file.txt
"Something evil\n"\
"this way comes!"
main.cpp
int main()
{
const char* text =
#include "file.txt"
;
printf("%s", text);
return 0;
}
So basically having a C or C++ style string in a text file that you include. It would make the code neater because there isn't this huge lot of text at the start of the file.
The title says it all. Like a compiler but not the same. I want a certain part of the code to be executed from an outer source in C++. And I don't know if that is even possible as it is in Javascript, Python etc.
Let's say I got a text file titled sample.txt like this:
int a = 10, c;
cin >> c;
cout << a + c;
And I'll call the text file in main() function and compiled the .exe file. When I run it, is it possible for it behave dynamically as if the code from the file is embedded in there and write 10 + input? The source file should be changed and different results will apply next time it runs. It's just an example piece of code by the way, I might want to run some for/while loops and if conditions etc.
PS: I know how to read from file and assign it as an integer or write it on the screen, that's not what I want. I need functions to be compiled through. Thanks.
There are a couple of approaches to this.
Fork a command-line compiler and the fork to run the result, passing input and output through STDIN/STDOUT
(While i realize you asked for this from a C++ calling program, i'm demonstrating the idea in bash for simplicity.)
File: run_it.sh:
#!/bin/bash
set -e # Bail on the first error
FN_IN=./sample.txt
FN_WRAPPED=./wrapped.cc
FN_EXE=./wrapped
CC=g++
# Wrap the fragment in a full C++ program and compile it.
function build_wrapper () {
cat > $FN_WRAPPED <<'EOF'
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
EOF
cat $FN_IN >> $FN_WRAPPED
cat >> $FN_WRAPPED <<'EOF'
return 0;
}
EOF
$CC -o $FN_EXE $FN_WRAPPED
}
# Run the wrapper, passing input through STDIN and reading the output from STDOUT.
function run () {
local IN=$1
echo $IN | $FN_EXE
}
# Remove the wrapper (both code and compiled).
function clean_up () {
rm -f $FN_WRAPPED $FN_EXE
}
build_wrapper
IN=24
OUT=$(echo "$IN" | $FN_EXE)
echo "Result = $OUT"
echo "Another result = $(run 16)"
clean_up
$ ./run_it.sh
Result = 34
Another result = 26
Use something like LLVM to compile the function in-process and call it
This approach is very powerful, but also somewhat involved.
In a nutshell, you'd want to
Read sample.txt into memory.
Compile it to a function.
Call the function.
Some possibly-helpful links:
http://fdiv.net/2012/08/15/compiling-code-clang-api
http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
http://llvm.org/docs/tutorial/
https://msm.runhello.com/p/1003
https://db.in.tum.de/teaching/ss15/moderndbs/resources/7/fibonacci.cpp
A compiled C++ program contains only the machine instructions necessary to execute the compiled source code, the language standard does not specify any mechanism for the user to produce additional machine instructions at run time.
In order to provide a scripting capability - the ability to generate program flow in response to the parsing of input text - you have to provide a parser and an execution engine.
int main()
{
std::string cmd;
int op1, op2;
while (cin >> cmd >> op1 >> op2) {
if (cmd == "add")
std::cout << op1 + op2 << "\n";
else if (cmd == "sub")
std::cout << op1 - op2 << "\n";
else
std::cerr << "error\n";
}
}
Many interpreted languages are written in C or C++ in the first place, so it is often possible to build them as a library which you can then incorporate into an application so that the program can call invoke them to provide an embedded scripting language. Common examples of such languages are Lua, Python and JavaScript. Your program can then pass code to be executed to the interpreter.
Writing your own lua interpreter could look like this:
#include <iostream>
#include <string>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
bool get_input(std::string& in)
{
bool result;
do {
std::cout << "lua> " << std::flush;
result = std::getline(std::cin, in);
} while (result && in.empty());
return result;
}
int main (void) {
lua_State *L = lua_open(); // open lua
luaL_openlibs(L); // open standard libraries
std::string in;
while (get_input(in)) {
if (in.empty())
continue;
int error = luaL_loadbuffer(L, in.c_str(), in.size(), "line") ||
lua_pcall(L, 0, 0, 0);
if (error) {
std::cerr << lua_tostring(L, -1) << '\n';
lua_pop(L, 1); // remove the error message from the stack
}
}
lua_close(L);
}
Under linux:
$ g++ -Wall -O3 -o mylua mylua.cpp -I/usr/include/lua5.1 -llua
$ ./mylua
lua> print("hello")
hello
lua> error
[string "line"]:1: '=' expected near '<eof>'
lua>
The following command runs fine on my embedded Linux (Beaglebone Black):
echo bone_pwm_P9_21 > /sys/devices/bone_capemgr.?/slots
But not when using this small C++ program:
#include <stdlib.h>
#include <string>
int main {
system(std::string("echo bone_pwm_P9_21 > /sys/devices/bone_capemgr.?/slots").c_str());
return 0;
}
The problem involves the '?' question mark, that is used as a wildcard.
When the question mark, in the std::string that is passed to system(), is replaced with a normal character, the system() function evaluates the command perfect.
Solutions I've tried without success:
replace ? with \?
replace ? with *
Apart from your code not being compilable, this fails because system(3) runs sh, often a minimal shell provided by dash or busybox.
Meanwhile, your interactive login uses bash, ksh or some other more comfy shell.
dash and busybox sh do not do glob expansion on redirections, while bash and ksh do. Here's a demonstration of the behavior you want courtesy of bash:
$ touch file.txt
$ bash -c 'echo "bash contents" > *.txt'
$ cat file.txt
bash contents
Meanwhile, the problem you're having with e.g. dash:
$ dash -c 'echo "and now dash" > *.txt'
$ ls
*.txt file.txt
$ cat '*.txt' # Instead of expanding, the path was taken literally
and now dash
$ cat file.txt
bash contents
To fix this, you can (in order of preference)
Write your C program in C code instead of shell script
Call a better shell with execve.
Rewrite to not write to a glob, e.g. echo "stuff" | tee *.txt > /dev/null
Call a better shell with system, e.g. bash -c "echo stuff > *.txt"
NOTE: As πάντα ῥεῖ pointed out the system() command calls the shell which will usually do the expansion when presented with the correct wildcard: *. This answer is thereful more appropriate if you want the control to make each system() call separately or if the underlying shell is limited.
Original answer:
Perhaps you could use wordexp for this to construct your strings before you make the system() call:
#include <string>
#include <vector>
#include <iostream>
#include <wordexp.h>
std::vector<std::string> expand_env(const std::string& var, int flags = 0)
{
std::vector<std::string> vars;
wordexp_t p;
if(!wordexp(var.c_str(), &p, flags))
{
if(p.we_wordc)
for(char** exp = p.we_wordv; *exp; ++exp)
vars.push_back(exp[0]);
wordfree(&p);
}
return vars;
}
int main()
{
for(auto&& s: expand_env("$HOME/*")) // <= Note the wildcard '*'
std::cout << s << '\n';
}
In your specific case you could perhaps use something like this:
int main()
{
std::vector<std::string> devices = expand_env("/sys/devices/bone_capemgr.*/slots");
for(std::vector<std::string>::size_type i = 0; i < devices.size(); ++i)
system(("echo bone_pwm_P9_21 > " + devices[i]).c_str());
}
I have the following problem:
I use in my program this function:
system("echo -n 60 > /file.txt");
it works fine.
But I don't want to have constant value. I do so:
curr_val=60;
char curr_val_str[4];
sprintf(curr_val_str,"%d",curr_val);
system("echo -n curr_val_str > /file.txt");
I check my string:
printf("\n%s\n",curr_val_str);
Yes,it is right.
but system in this case doesn't work and doesn't return -1. I just print string!
How can I transfer variable like integer that will be printed in file like integer, but don't string?
So I want to have variable int a and I want to print value of a with system function in file. A real path to my file.txt is /proc/acpi/video/NVID/LCD/brightness. I can't write with fprintf. I don't know why.
you cannot concatenate strings like you are trying to do. Try this:
curr_val=60;
char command[256];
snprintf(command, 256, "echo -n %d > /file.txt", curr_val);
system(command);
The system function takes a string. In your case it's using the text *curr_val_str* rather than the contents of that variable. Rather than using sprintf to just generate the number, use it to generate the entire system command that you require, i.e.
sprintf(command, "echo -n %d > /file.txt", curr_val);
first ensuring that command is large enough.
The command that is actually (erroneously) executed in your case is:
"echo -n curr_val_str > /file.txt"
Instead, you should do:
char full_command[256];
sprintf(full_command,"echo -n %d > /file.txt",curr_val);
system(full_command);
#define MAX_CALL_SIZE 256
char system_call[MAX_CALL_SIZE];
snprintf( system_call, MAX_CALL_SIZE, "echo -n %d > /file.txt", curr_val );
system( system_call );
man snprintf
The correct way would be similar to this:
curr_val=60;
char curr_val_str[256];
sprintf(curr_val_str,"echo -n %d> /file.txt",curr_val);
system(curr_val_str);
Just DON'T. :)
Why resort to system() for such a simple operation?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int write_n(int n, char * fname) {
char n_str[16];
sprintf(n_str, "%d", n);
int fd;
fd = open(fname, O_RDWR | O_CREAT);
if (-1 == fd)
return -1; //perror(), etc etc
write(fd, n_str, strlen(n_str)); // pls check return value and do err checking
close(fd);
}
Have you considered using C++'s iostreams facility instead of shelling out to echo? For example (not compiled):
std::ostream str("/file.txt");
str << curr_val << std::flush;
Alternately, the command you pass to system must be fully formatted. Something like this:
curr_val=60;
std::ostringstream curr_val_str;
curr_val_str << "echo -n " << curr_val << " /file.txt";
system(curr_val_str.str().c_str());
Use snprintf to avoid security issues.
What about using std::string & std::to_string...
std::string cmd("echo -n " + std::to_string(curr_val) + " > /file.txt");
std::system(cmd.data());