Converting string to long using strtol and pointers - c

My goal is to convert a string such as "A1234" to a long with value 1234. My first step was to just convert "1234" to a long, and that works as expected:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char* test = "1234";
long val = strtol(test,NULL,10);
char output[20];
sprintf(output,"Value: %Ld",val);
printf("%s\r\n",output);
return 0;
}
Now I am having trouble with pointers and trying to ignore the A at the beginning of the string. I have tried char* test = "A1234"; long val = strtol(test[1],NULL,10); however that crashes the program.
How do I set this up properly to get it pointing to the correct spot?

You are almost right. You need to pass a pointer to strtol, though:
long val = strtol(&test[1], NULL, 10);
or
long val = strtol(test + 1, NULL, 10);
Turning on some compiler warning flags would have told you your problem. For example, from clang (even with no special flags added):
example.c:6:23: warning: incompatible integer to pointer conversion passing
'char' to parameter of type 'const char *'; take the address with &
[-Wint-conversion]
long val = strtol(test[1],NULL,10);
^~~~~~~
&
/usr/include/stdlib.h:181:26: note: passing argument to parameter here
long strtol(const char *, char **, int);
^
1 warning generated.
and from GCC:
example.c: In function ‘main’:
example.c:6: warning: passing argument 1 of ‘strtol’ makes pointer from integer
without a cast
Editorial note: I think you can see from these error messages why beginners are often well-advised to use clang rather than GCC.

Related

How to trigger an integer conversion warning when passing an enum instead of a pointer

Given the following code
#include <stdio.h>
typedef enum{
ISP_INPUT_NONE,
ISP_INPUT_DOLBY
} UserStream_t;
int someFunc(const char * str) {
printf("%s", str);
return 0;
}
int main(int argc, char** arg)
{
int a = ISP_INPUT_NONE;
someFunc(ISP_INPUT_NONE);
someFunc(a);
return 0;
}
The second call triggers an integer conversion warning, but the first doesn't.
gcc -Wall test.c
test.c: In function ‘main’:
test.c:17:14: warning: passing argument 1 of ‘someFunc’ makes pointer from integer without a cast [-Wint-conversion]
17 | someFunc(a);
| ^
| |
| int
test.c:8:27: note: expected ‘const char *’ but argument is of type ‘int’
8 | int someFunc(const char * str) {
| ~~~~~~~~~~~~~^~~
Are enum silently converted to pointers?
I thought C enums were considered as integers. I would like the first call to generate the same warning as the second.
Are enum silently converted to pointers ?
Well, some of them. ISP_INPUT_NONE is 0 and enumeration values are constant expressions and a constant expression with the value 0 is a null pointer constant. And converting a null pointer constant to another pointer is just normal.
The warning will still be issued if the enum value is not 0, for example for someFunc(ISP_INPUT_DOLBY);.
How to trigger integer conversion warning when passing enum instead of pointer
Ideas:
Start enum with 1 instead of 0.
typedef enum {
ISP_INPUT_NONE = 1,
ISP_INPUT_DOLBY
} UserStream_t;
Use a structure and have conversion errors.
typedef struct {
unsigned char val;
} UserStream_t;
static const UserStream_t ISP_INPUT_NONE = {0};
static const UserStream_t ISP_INPUT_DOLBY = {1};
Some way use a macro so that ISP_INPUT_NONE is not a constant expression.
static int entity(int a) { return a; }
typedef enum{
ISP_INPUT_NONE,
#define ISP_INPUT_NONE (entity(ISP_INPUT_NONE))
ISP_INPUT_DOLBY
} UserStream_t;
Use clang compiler with -Wnon-literal-null-conversion option.
In g++ there is -Wzero-as-null-pointer-constant option, but no such option for C in gcc. You could also make a feature request to gcc.

Shortest method to pass arguments to argv pointer

I wrote three ways of passing arguments to a function that accepts argv argument.
The first method of using string literals is the shortest and works fine, but gives me a deprecated warning as my test harness is cpp based:
error: conversion
from string literal to 'char *' is deprecated
[-Werror,-Wc++11-compat-deprecated-writable-strings]
The method using malloc works, though it's a tad bit longer.
The last method causes a seg fault. Can you help me figure out the mistake in the third method, where I create an array with predefined size and copy the contents? Why does it fail?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEST3
int console_tester(int argc, char *argv[])
{
printf("argv: %s\n", argv[0]);
return 0;
}
int main()
{
#ifdef TEST1
// works, shortest, but gives compilation warnings
char *test_cmd[2] = {"hello1", "hello2"};
int result = console_tester(2, (char**)test_cmd);
#endif
// works, verbose
#ifdef TEST2
char *test_cmd[2];
test_cmd[0] = malloc(10);
test_cmd[1] = malloc(10);
memset(test_cmd[0], 0, 10);
memset(test_cmd[0], 1, 10);
memcpy(test_cmd[0], "hello1", sizeof("hello1"));
memcpy(test_cmd[1], "hello2", sizeof("hello2"));
int result = console_tester(2, (char**)test_cmd);
free(test_cmd[0]);
free(test_cmd[1]);
#endif
// crash and burn
#ifdef TEST3
char test_cmd[2][10];
memset(&test_cmd[0], 0, 10);
memset(&test_cmd[1], 0, 10);
memcpy(&test_cmd[0], "hello1", sizeof("hello1"));
memcpy(&test_cmd[1], "hello2", sizeof("hello2"));
int result = console_tester(2, (char**)test_cmd);
#endif
return 0;
}
In the third example you're doing an invalid conversion:
char test_cmd[2][10];
memset(&test_cmd[0], 0, 10);
memset(&test_cmd[1], 0, 10);
memcpy(&test_cmd[0], "hello1", sizeof("hello1"));
memcpy(&test_cmd[1], "hello2", sizeof("hello2"));
int result = console_tester(2, (char**)test_cmd);
This produces a compiler warning for me when I strip off the (char**) brute-force casting:
warning: incompatible pointer types passing 'char (*)[10]' to parameter of type 'char **' [-Wincompatible-pointer-types]
Which really should be an error. You can't switch those arbitrarily. You don't have the right kind of structure to pass in, so you must convert it to the correct structure first.
The other two examples both use char** properly so they're fine.
This is why turning on all warnings your compiler has to offer can help narrow down problems quickly. C, and by extension C++, really does not care if you're asking to do something invalid, it'll do it if told to do it, and then crash or act really strange because of it.

Vala: warning and segmentation fault with to_utf32_fast method

I got a warning and a segmentation fault when compiling and running roughly the following code, which uses the to_utf32_fast method on a string and should return the number of UTF-32 characters encoded in the codepoint_count variable. This method transpiles to the C function g_utf8_to_ucs4_fast and somehow out codepoint_count ends up as long * * argument instead of the expected long *.
I do have a workaround, so this isn't urgent.
int main (string[] args) {
string test = "abc";
long codepoint_count;
string utf32_version = test.to_utf32_fast(-1, out codepoint_count).to_string();
stdout.printf("success");
return 0;
}
The relevant part of the output:
C:/msys64/usr/src/outerror.vala.c: In function '_vala_main':
C:/msys64/usr/src/outerror.vala.c:78:50: warning: passing argument 3 of 'g_utf8_to_ucs4_fast' from incompatible pointer type [-Wincompatible-pointer-types]
_tmp2_ = g_utf8_to_ucs4_fast (test, (glong) -1, &_tmp1_);
^
In file included from C:/msys64/mingw64/include/glib-2.0/glib/gstring.h:33:0,
from C:/msys64/mingw64/include/glib-2.0/glib/giochannel.h:34,
from C:/msys64/mingw64/include/glib-2.0/glib.h:54,
from C:/msys64/usr/src/outerror.vala.c:5:
C:/msys64/mingw64/include/glib-2.0/glib/gunicode.h:798:12: note: expected 'glong * {aka long int *}' but argument is of type 'glong ** {aka long int **}'
gunichar * g_utf8_to_ucs4_fast (const gchar *str,
^~~~~~~~~~~~~~~~~~~
I looked at the transpiled C source code and the third argument to g_utf8_to_ucs4_fast is the address of an uninitialized pointer to long which is later freed with g_free. This triggers a segfault when the program is run.
Am I doing something wrong in the way I'm calling this function? It's declared as public string32 to_utf32_fast (long len = -1, out long? items_written = null).
I'm new to Vala (more familiar with C) and not sure I grasp the argument annotations. The second argument shouldn't be transpiled to C as long ** rather than long *, but maybe the nullability marker ? or the default value = null leads Vala to think that the variable items_written is a pointer to long (or the Vala equivalent thereof) rather than long. If so, then maybe there is an error in the declaration of the method or an ambiguity in Vala syntax.
The declaration is wrong. This code works just fine:
[CCode (cname = "g_utf8_to_ucs4_fast")]
public extern string32 to_utf32_fast_ (string s, long len = -1,
out long items_written);
int main (string[] args) {
string test = "abc";
long codepoint_count;
string32 utf32_version = to_utf32_fast_(test, -1, out codepoint_count);
stdout.printf("success");
return 0;
}
In the original declaration from glib-2.0.vapi the items_written parameter would be a glong** in C, but it actually is a glong*.
I have reported this as a bug:
https://gitlab.gnome.org/GNOME/vala/issues/634

Cannot Use Printf!?! (while performing hashing algorithm using mhash)

I am using Mhash and I would like to print the length of my blocksize for debugging purposes, but I keep getting an error every time I try to compile
Any suggestions on how I can fix this error?
Here is my code:
#include <mhash.h>
#include <stdio.h>
#include <string.h>
// 0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179 (TIGER192) (48)
int main()
{
char password[] = "Jefe";
int keylen = 4;
char data[] = "what do ya want for nothing?";
int datalen = 28;
MHASH td, td2;
unsigned char *mac, *mac2;
int i, j;
td = mhash_hmac_init(MHASH_TIGER192, password, keylen, mhash_get_hash_pblock(MHASH_TIGER192));
mhash(td, data, datalen);
mac = mhash_hmac_end(td);
printf("0x");
for (i = 0; i < mhash_get_block_size(MHASH_TIGER192); i++)
{
printf("%.2x", mac[i]);
}
printf("\n");
// int length = strlen(mac);
// printf(length);
// int length = 5;
// printf(length);
exit(0);
}
I run the program with the following commands:
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hb2#hb1:~/Desktop$ ./hashexample
0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179
And it runs successfully, but when I try to print the length of the hashed result, I get the following error!!? Any ideas on why?
// int length = strlen(mac);
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:33:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:33:2: warning: format not a string literal and no format arguments [-Wformat-security]
At first, I thought it was because I thought I was using strlen incorrectly?! But even when I try to do a simple printf of an integer, I still get an error:
// int length = 5;
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:35:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:35:2: warning: format not a string literal and no format arguments [-Wformat-security]
Thanks for your help in advance!
Check the man page for printf(). The first argument is a const char *. You're passing an int.
That's what the warning says too:
warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
You wanted:
printf("%d", length);
You need the format string to specify that an int is going to be printed.

Fix incompatible-pointer-types warning

Bonjour, I keep getting this warning, and I've tried everything to fix the warning w/o any result. The program still works, but the warning is annoying and I'd love to know the "why".
It's a table, takes input from the user for a position in the table, and uses that position in the function encuentRuta.
This is (part of) the code:
char encuentRuta (int posv, int posh, char lab[TAMV][TAMH]);
int main (int argc, char *argv[]) {
int altura = atoi(argv[1]);
int base = atoi(argv[2]);
/* Define the table */
char laberinto[TAMV][TAMH] = {LABERINTO};
encuentRuta (altura, base, &laberinto);
And the error I keep getting is:
> warning: incompatible pointer types passing 'char (*)[8][12]'
> to parameter of type 'char (*)[12]' [-Wincompatible-pointer-types]
> encuentRuta (altura, base, &laberinto);
> ^~~~~~~~~~
> laberinto.c:16:44: note: passing argument to parameter 'lab' here
> char encuentRuta (int posv, int posh, char lab[TAMV][TAMH]);
Thanks for the help.
Omit the & before laberinto in the call to encuentRuta().
The message does its best to explain it to you. If you take the address of a 2D array (&laberinto), you get a pointer to an array, which is written SomeType (*)[size1][size2], or char (*)[8][12] in your example. To pass an array, you simply name it:
encuentRuta(altura, base, laberinto);

Resources