I am working on a project that uses non standard C Libraries to display the output on an LCD screen. I have the code working great but I have run into a problem.
What my intended purpose of this program is to do is take a command line string of text and convert it to the ASCII decimal values then display them on the screen. The way that you output text to the screen is by making a call to the serialPutchar function so to display the letter H I would write it as serialPutchar(fd, 'H'); I want to be able to get the values from variables and output the letters in the variable.
The problem is that when I write it as serialPutchar(fd, "%c", H); or try serialPutchar(fd, "%d", x); I get the following error:
testing.c: In function âmainâ:
testing.c:22:3: warning: passing argument 1 of âserialPutcharâ makes integer from pointer without a cast [enabled by default]
/usr/local/include/wiringSerial.h:30:14: note: expected âintâ but argument is of type âchar *â
testing.c:22:3: error: too many arguments to function âserialPutcharâ
/usr/local/include/wiringSerial.h:30:14: note: declared here
I'm guessing it cant be used in that fashion like you would use printf so is there an alternative to this or maybe I just have a simple error I am not spotting. I am including a link to the documentation for the wiringSerial library. Also from my error output I am getting the strange characters around the error testing.c In function main: and several other lines. Is there a way to prevent this? Link to library HERE Below is my working code to output HELLO:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main (int argc, char *argv[])
{
int fd ;
if ((fd = serialOpen ("/dev/ttyAMA0", 9600)) < 0)
{
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
if (wiringPiSetup () == -1)
{
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
int H = 1;
serialPutchar(fd, 'H');
serialPutchar(fd, 'E');
serialPutchar(fd, 'L');
serialPutchar (fd, 'L');
serialPutchar (fd, 'O');
}
:::UPDATE:::
Here is the working code that fit my description:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main (int argc, char *argv[])
{
int fd ;
if ((fd = serialOpen ("/dev/ttyAMA0", 9600)) < 0)
{
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
if (wiringPiSetup () == -1)
{
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
for (int i=1; i<argc; i++){
serialPrintf (fd, "%s", argv[i]);
}
}
putChar takes a char as its second argument. Not a string, not a format string with arguments, just a char.
If you have a char in a variable x, just do:
serialPutchar(fd, x);
Related
I've read some of the warnings against using the sysctl() call in C, and it seems if I cannot use sysctl() safely, the only other way I can find to make the needed change would be to use soemething like:
system("echo fs.inotify.max_user_watches=NEW_MAX_DIRECTORIES >> /etc/sysctl.conf");
system("sysctl -p");
(of course, this assumes ensuring the binary is running as root. However, I would rather NOT have to shell out using system calls.
Can someone point me in the correct and safe of using sysctl()?
here is a snippet of the code I am using.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
int main ()
{
int ret;
const char *LOGNAME="iNotifyMonitor";
logger(INFO, "================================================");
ret = startDaemon();
daemonRunning = ret;
if (ret == 0)
{
daemonRunning = 1;
FIRST_RUN = 0;
}
if(ret)
{
syslog(LOG_USER | LOG_ERR, "Error starting iNotifyMonitor");
logger(ERR, "Unable to start iNotifyMonitor");
closelog();
return EXIT_FAILURE;
}
signal(SIGINT, signalHandler);
signal(SIGHUP, signalHandler);
char *log_file_name = malloc(sizeof(char *) * sizeof(char *));
sprintf(log_file_name, "%s%s", INM_LOG_DIR, INM_LOG_FILE);
/* Try to open log file to this daemon */
if (INM_OPEN_LOG && INM_LOG_FILE)
{
log_stream = fopen(concatString(INM_LOG_DIR, INM_LOG_FILE), "a+");
if (log_stream == NULL)
{
char *errMsg;
sprintf(errMsg, "Cannot open log file %s, error: %s", concatString(INM_LOG_DIR, INM_LOG_FILE), strerror(errno));
log_stream = stdout;
}
}
else
{
log_stream = stdout;
}
while (daemonRunning == 1)
{
if (ret < 0)
{
logger(LOG_ERR, "Can not write to log stream: %s, error: %s", (log_stream == stdout) ? "stdout" : log_file_name, strerror(errno));
break;
}
ret = fflush(log_stream);
if (ret != 0)
{
logger(LOG_ERR, "Can not fflush() log stream: %s, error: %s",
(log_stream == stdout) ? "stdout" : log_file_name, strerror(errno));
break;
}
int curcount =countDirectory("/home/darrinw/Development/CrossRoads/");
directoryCount = curcount;
if(directoryCounrt > INM_MAX_DIRECTORIES)
{
int newVal = roundUp(directoryCount, 32768);
// call to sysctl() to modify fs.inotify.max_users_watches=newVal
}
sleep(INM_SCAN_INTERVAL);
}
My understanding is that the modern recommended approach to access sysctl variables is via the pseudo-files in /proc/sys. So just open /proc/sys/fs/inotify/max_user_watches and write there.
int fd = open("/proc/sys/fs/inotify/max_user_watches", O_WRONLY);
dprintf(fd, "%d", NEW_MAX_DIRECTORIES);
close(fd);
Error checking left as an exercise.
Modifying /etc/sysctl.conf would make the setting persist across reboots (assuming your distribution uses the file this way, I am not sure if all of them do). That's kind of rude to do automatically; probably better to use the documentation to advise the system administrator to do it themselves if it's needed.
I have to make a custom shell as a school project and I'm hitting a wall with this:
int exec_shell(char **argv) //
{
if (execve(argv[0], (char **)argv , NULL)==-1) //if an error occurs
{
printf("Commande invalide : %s\n", argv[0]);
fflush(stdout);//vide le buffer
exit(0);
return -1;
}
return 0;
}
It's supposed to be very simple - you put in a command in string form and exec calls the said command.
However, it always returns an error.
What am I doing wrong?
Here is the single warning:
primitives.c:25:30: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Step : 1
/* myecho.c */
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
int j;
for (j = 0; j < argc; j++)
printf("argv[%d]: %s\n", j, argv[j]);
exit(EXIT_SUCCESS);
}
Compile Program : gcc myecho.c -o myecho
step : 2
/* execve.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
char *newargv[] = { NULL, "hello", "world", NULL };
char *newenviron[] = { NULL };
if (argc != 2) {
fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
exit(EXIT_FAILURE);
}
newargv[0] = argv[1];
if (execve(argv[1], newargv , newenviron) == -1) //if an error occurs
{
printf("Commande invalide : %s\n", argv[0]);
fflush(stdout);//vide le buffer
exit(0);
return -1;
}
}
compile program : gcc execve.c -o execve
step: 3 //Final call
./execve ./myecho
step: observe output.
To pass an empty environment either define and pass
char * env[] = { NULL };
as third parameter to execve() like this
execve(argv[0], argv, env)
or use a compound literal by doing
execve(argv[0], argv, (char*[]){NULL})
Also the members of the exec*() family of functions only return on error, so the surrounding code might look like this:
int main(void)
{
...
execve(argv[0], argv, (char*[]){NULL});
perror("execve() failed");
return EXIT_FAILURE; /* include stdlib.h to have this macro available */
}
[RESOLVED] Hey, I would like to thank you all for your answer. It helped me figure out better what was wrong and I found an answer here.
The main issue was the path not being correct.
I have a piece of code to create function to print a message from input parameter.
I've been compiling the code with c9.io and works pretty well without warnings but when i do it locally it shows a warning like this:
child2bok: c39:11: warning: Ignoring return value of 'write', declares with attribute warn_unused_result [-Wunused -result]
And this is the code.Sure it is a problem with write() definition but i'm so novice with unix programming and no idea to solve it. It executes well but i'd like to remove the warning before i deliver to the teacher.
Here you are the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include "rutines.h"
void children();
void show_help();
int main(int argc, char *argv[])
{
int ord;
if (argc > 1)
ord = atoi(argv[1]);
if (argc == 1)
{
show_help("Error");
exit(1);
}
children(ord);
}
void children(int ord)
{
char msg[10];
srand(getpid());
sleep(rand() % 5);
sprintf(msg, " %d", ord);
while (strlen(msg) > 0)
{
int written= write(1, msg, strlen(msg));
if (written < 0)
break;
exit(0);
}
void show_help(char *err_message)
{
write_string(err_message,"");
write_string("Usage: child2aok \n","");
}
You should check and handle the value returned by the write() command. From the write documentation:
write [...] may return less than count even under valid conditions.
Why don't you simply use printf(" %d", ord); instead of sprintf(msg, " %d", ord); write(1, msg, strlen(msg))?
write does not guarantee to write all the data; it may write as little as one byte (or block, or return an error, ...). So you have to use it in a loop:
bool write_all(int fd, void * buf, size_t len)
{
size_t remaining = len;
for (size_t n; (n = write(fd, buf, remaining)) > 0; remaining -= n)
{ }
return remaining == 0;
}
This function returns true if all bytes were written, and false on error.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int fd, offset;
char *data;
struct stat sbuf;
int counter;
if (argc != 2) {
fprintf(stderr, "usage: mmapdemo offset\n");
exit(1);
}
if ((fd = open("mmapdemo.c", O_RDONLY)) == -1) {
perror("open");
exit(1);
}
if (stat("mmapdemo.c", &sbuf) == -1) {
perror("stat");
exit(1);
}
offset = atoi(argv[1]);
if (offset < 0 || offset > sbuf.st_size-1) {
fprintf(stderr, "mmapdemo: offset must be in the range 0-%ld\n",sbuf.st_size-1);
exit(1);
}
data = mmap((caddr_t)0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (data == (caddr_t)(-1)) {
perror("mmap");
exit(1);
}
// print the while file byte by byte
while(counter<=sbuf.st_size)
printf("%c", data++);
return 0;
}
This gives me error as follows:
gcc mmapdemo.c -o mmapdemo
mmapdemo.c: In function 'main':
mmapdemo.c:48: warning: format '%c' expects type 'int', but argument 2 has type 'char *'
Please help me to solve the problem.
printf("%c", *data++);
data is a char *. The %c format specifier tells printf to expect a char. To get a char from a char *, you need to dereference the pointer using the * operator.
That said, your program still won't work properly because you're not incrementing counter in your print loop, nor have you initialized it. I would go with:
for (size_t i = 0; i < sbuf.st_size; ++i) {
printf("%c", data[i]);
}
instead. I haven't inspected the rest of your program, but given that there were three serious errors in three lines that I looked at, I doubt that the rest is bug-free.
to print it out byte by byte, need to use
printf("%c ", *data++)
or to print out the hex values:
printf("%02X", *data++);
Now I do have a hw question for everyone...I've been staring at this for a couple of days kind of tinkering and playing around but even with that I end up with a load of errors...
What I'm trying to do is take the program below and change it so that it takes an optional command line argument infile. If infile is given, then copy infile to standard output, otherwise copy standard input to standard output as before.
The trick about this is that the solution must use the original copy loop (lines 9-11) for both cases. One can only insert code, and not change any of the existing code. Any help would be great. Thanks.
/* $begin cpfile */
include "csapp.h"
int main(int argc, char **argv)
{
int n;
rio_t rio;
char buf[MAXLINE];
Rio_readinitb(&rio, STDIN_FILENO); //line 9
while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) //line 10
Rio_writen(STDOUT_FILENO, buf, n); //line 11
/* $end cpfile */
exit(0);
/* $begin cpfile */
}
/* $end cpfile */
C programs get command line arguments through the two arguments to main(), traditionally called argc and argv (for argument count and argument vector, respectively).
Arguments are not "named" anything, they're just strings.
A solution for you could look like this:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fileno;
/* ... your definitions should remain here, too */
if(argc > 1)
{
/* Assume first argument is filename, and open it. */
fileno = open(argv[1], O_RDONLY);
if(fileno < 0)
{
printf("Unable to open file, aborting\n");
return 1;
}
}
else
fileno = STDIN_FILENO;
/* ... your code goes here ... */
}
Then you'd of course need to change the call to Rio_readinitb() to use the fileno variable for the file descriptor.
If you literally can't change that line, for whatever reason ... I guess you can use the preprocessor to make the symbol evaluate to the new variable name:
#undef STDIN_FILENO
#define STDIN_FILENO fileno
This is of course not exactly pretty, but should work.
Make sure you put those preprocessor macros after the fileno = STDIN_FILENO; line.
You can insert dup2 before the lines 9 - 11 and it seems that you will not need change code on the lines 9 - 11. This is an example.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int file_handle;
int dup2_res;
if (argc == 2) {
file_handle = open(argv[1], O_RDONLY);
dup2_res = dup2 (file_handle, STDIN_FILENO);
}
char buffer[100];
ssize_t read_bytes = 1;
while (read_bytes)
{
read_bytes = read(STDIN_FILENO, &buffer, sizeof(buffer) );
buffer[read_bytes] = 0;
printf("%s", buffer);
}
close(file_handle);
return 0;
}
If STDIN_FILENO cannot be reassigned, it sounds like a task for freopen():
freopen(argv[1], "r", stdin);