Why does this code work on Linux but not on SunOS? - linux

#include <stdio.h>
int main() {
char *str = "11111111-22222222 r-xp 00000000 00:0e 1843624 /lib/libdl.so.0";
unsigned long long start_addr, stop_addr, offset;
char* access = NULL;
char* filename = NULL;
sscanf(str, "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms",
&start_addr, &stop_addr, &access, &offset, &filename);
printf("\n start : %x, stop : %x, offset : %x\n",start_addr,stop_addr,offset);
printf("\n Permission : %s\n",access);
printf("\n Filename : %s\n",filename);
return 0;
}
On Linux this gives the correct output but on Solaris the file is called libdl.so (there is no libdl.so.0 on Solaris) so I wonder what makes this difference, there is not this file on Solaris and if I change to the filename of the Solaris installation (libdl.so) then it generates a segmentation fault.
$ cc Cperm.c ;./a.out
Cperm.c: I funktion "main":
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 3 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 4 har typen "long long unsigned int" [-Wformat]
start : 11111111, stop : 22222222, offset : 0
Permission : r-xp
Filename : /lib/libdl.so.0
The above is on ubuntu and here is on Solaris where it compiles without warnings but generates a segmentation fault:
uname -a
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
my:~>cc Cperm.c;./a.out
start : 0, stop : 11111111, offset : 0
Segmentation fault
Update
my:~>uname -a;gcc -Wall Cperm.c
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
Cperm.c: In function `main':
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: long long unsigned int format, pointer arg (arg 5)
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: too many arguments for format
Cperm.c:11: warning: unsigned int format, different type arg (arg 2)
Cperm.c:11: warning: unsigned int format, different type arg (arg 3)
Cperm.c:11: warning: unsigned int format, different type arg (arg 4)
my:~>gcc Cperm.c
my:~>

Check the man page for Solaris 10 sscanf. The %m modifier is not supported there.
You should also check the return value of sscanf.

Your compiler (on Ubuntu, and probably Solaris if you enabled the warning) told you what is wrong:
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
⋮
You need to use %llx in your printf, just like you did in your sscanf.
Passing the wrong type of argument is undefined behavior. On Linux, it happened to work (this time); on Solaris, it didn't.
[You're really asking a question about the C language and libraries, you'd probably have better luck searching Stack Overflow for answers, rather than here.]
edit: see also msw's answer, which points out another problem, at least as important as this one.

It's actually much simpler than it might look. Your code has never allocated space to store the string results into. This shorter code has the same defect:
#include <stdio.h>
int main() {
char *word = NULL;
sscanf("hello world", "%s", &word);
printf("%s\n", *word);
return 0;
}
The reason it may "work" on one compiler but not another may have to do with how storage is allocated. Here is the error generated by that code:
cperm.c:5:5: error: format ‘%s’ expects argument of type ‘char *’,
but argument 3 has type ‘char **’
Which doesn't seem horrible, but it's actually fatal. Running gcc with the -Werror option would make that warning stop compilation and not create an a.out. Defining and using word properly
char word[64];
sscanf("hello world", "%63s", word);
printf("%s\n", word);
compiles without error and works.

Related

Building String from UART Characters - Home Learning C

I'm working with a PIC and have successfully got a single character received over the UART, however I now need to capture a incoming sequence of characters, build up a string and perform a action after receiving a carrage return. I have some prior experience with PHP and thought things would be much easier than its turned out to be.
I've modified my simple code with the working UART functions to attempt to concatinate the received characters as follows and build up a string:
#include "mcc_generated_files/mcc.h"
#include "string.h"
unsigned char InChar;
char Temp[5];
char Command[32];
void UART_Demo_Command_INT(void)
{
if(eusartRxCount!=0)
{
InChar=EUSART_Read(); // read a byte for RX
strcat(Command,InChar); //concat Command with InChar, result in Command
printf = printf("Command String: %s \n", Command);
}
}
I'm receiving a number of errors:
UART_Demo.c:115:24: warning: incompatible integer to pointer conversion passing 'unsigned char' to parameter of type 'const char *' [-Wint-conversion]
strcat(Command,InChar); //concat Command with InChar, result in Command
^~~~~~
C:\Program Files (x86)\Microchip\xc8\v2.10\pic\include\c99\string.h:36:55: note: passing argument to parameter here
char *strcat (char *__restrict, const char *__restrict);
^
UART_Demo.c:116:16: error: non-object type 'int (const char *restrict, ...)' is not assignable
printf = printf("Command String: %s \n", Command);
~~~~~~ ^
1 warning and 1 error generated.
After spending a number of hours trying to fix this and getting nowhere I'm hoping some of you can help.
If anyone's interested the problem was because my received characters are just...characters, not a string which would normally have a termination \0 character at the end, therefore the strcat (Concatinate strings) function didn't work.
As a fix I just added \0 to the end of InChar then strcat worked.

GCC interprets uint8_t and uint16_t as signed? [duplicate]

This question already has answers here:
Format specifiers for uint8_t, uint16_t, ...?
(7 answers)
Closed 3 years ago.
My test code:
#include <cstdint>
#include <cstdio>
int main() {
const constexpr uint8_t x = 64;
printf("%u", x);
}
Here is how I compiled with GCC 8.2:
g++ -Wall test_format.cpp -o test_format -O3 -std=c++17 -Wformat-signedness
And here is GCC's output:
test_format.cpp: In function ‘int main()’:
test_format.cpp:6:9: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int’ [-Wformat=]
printf("%u", x);
^~~~
Tho, if I try to print an uint32_t, it has no error/warning.
I wonder why GCC expects uint8_t to be signed int.
Thanks.
Default argument promotions are applied to operands of a variadic function. Under these, an expression of type unsigned char is promoted to int.
In C and C++ types narrower than int are always promoted to int. See Why must a short be converted to an int before arithmetic operations in C and C++?
And inside variadic functions default promotion also applies, which means you can't pass types narrower than int to vararg functions. So uint8_t must be printed with %d, not %u. But anyway you're printing it the wrong way. The correct way is to use PRIu8
printf("%" PRIu8 "\n", x);
Format specifiers for uint8_t, uint16_t, ...?
printing the uint8_t
Why is the format specifier for uint8_t and uint16_t the same (%u)?
How do I print uint32_t and uint16_t variables value?
To print a uint8_t variable with printf(), you should do something like the following:
#include <cinttypes>
#include <cstdio>
int print_u8(std::uint8_t x) {
return std::printf("%" PRIu8 "\n", x);
}
The <cinttypes> header includes printf and scanf format specifiers for all the <cstdint> types (and explicitly includes that header) that should be used for maximum portability.

why typedef throwing error :(S) Initializer must be a valid constant expression

in f1.h header using typedef for structure. sample code snippet shown below
typedef struct{
int a;
union u
{
int x;
char y;
}xyz;
}mystruct;
In f2.h header using the structure mysturct to get the offset. Code snippet shown below
static mystruct ktt
//#define OFFSET_T(b, c) ((int*)((&((mystruct*)0)->b)) - (int*)((&((mystruct*)0)->c)))
#define OFFSET_T(b, c) ((char*) &ktt.b - (char *) &ktt.c)
static struct Mystruct1{
int n;
}mystruct1 = {OFFSET_T(xyz,a)};
when i'm doing compilation in AIX machine using xlc compiler it is throwing the error as "1506-221(S) Initializer must be a valid constant expression".
i tried both the macro's but both are getting same error. Is there anything wrong in f2.h macro while performing size of structure to get offset ??
The expression in question needs to be an arithmetic constant expression in order to be portable. Neither macro qualifies, since operands of pointer type are involved and arithmetic constant expressions are restricted such that those operands are not allowed. In C11, this is found in subclause 6.6 paragraph 8.
That said, the code using the first macro (source reproduced below) does compile on multiple versions of the xlc compiler on AIX.
typedef struct{
int a;
union u
{
int x;
char y;
}xyz;
}mystruct;
static mystruct ktt;
#define OFFSET_T(b, c) ((int*)((&((mystruct*)0)->b)) - (int*)((&((mystruct*)0)->c)))
//#define OFFSET_T(b, c) ((char*) &ktt.b - (char *) &ktt.c)
static struct Mystruct1{
int n;
}mystruct1 = {OFFSET_T(xyz,a)};
The compiler invocation I used was:
xlc offsetcalc.c -c -o /dev/null
The version information for one of the older versions I tried is:
IBM XL C/C++ for AIX, V10.1
Version: 10.01.0000.0021
The version information for one of the newest versions I tried is:
IBM XL C/C++ for AIX, V13.1.3 (5725-C72, 5765-J07)
Version: 13.01.0003.0004

GNU inline assembly to move data

I want to write a 64 bit integer to a particular memory location.
sample C++ code would look like this:
extern char* base;
extern uint64_t data;
((uint64_t *)base)[1] = data;
Now, here is my attempt to write the above as inline assembly:
uint64_t addr = (uint64_t)base + 8;
asm volatile (
"movq %0, (%1)\n\t"
:: "r" (data), "r"(addr) : "memory"
);
The above works in a small test program but in my application, I suspect that something here is off.
Do I need to specify any output operands or any other constraints in the above?
Thanks!
Just say:
asm("mov %1, %0\n\t" : "=m"(*(uint64_t*)(base + 8)) : "r"(data) : "memory");
The tricky thing is that when using the "m" constraint, you're (possibly counterintuitively so) not giving an address but instead what in C looks like the "value" of the variable you want to change.
That's why, in this case, the weird pointer-cast-dereference. The compiler for this makes sure to put the address of the operand in.

Segmentation fault while trying to print parts of a pointer struct

I'm writing a program that must take user input to assign values to parts of a structure. I need to create a pointer to the structure that I will pass through as a one and only parameter for a function that will print each part of the structure individually. I also must malloc memory for the structure. As it is now, the program compiles and runs through main and asks the user for inputs. A segmentation fault occurs after the last user input is collected and when I'm assuming the call to the printContents function is run. Any help would be appreciated!
#include <stdio.h>
#include <stdlib.h>
struct info
{
char name[100], type;
int size;
long int stamp;
};
void printContents(struct info *iptr);
int main(void)
{
struct info *ptr=malloc(sizeof(struct info));
printf("Enter the type: \n");
scanf("%c", &(*ptr).type);
printf("Enter the filename: \n");
scanf("%s", (*ptr).name);
printf("Enter the access time: \n");
scanf("%d", &(*ptr).stamp);
printf("Enter the size: \n");
scanf("%d", &(*ptr).size);
printf("%c", (*ptr).type);
printContents(ptr);
}
void printContents(struct info *iptr)
{
printf("Filename %s Size %d Type[%s] Accessed # %d \n", (*iptr).name, (*iptr).size, (*iptr).type, (*iptr).stamp);
}
Check the operator precedence. Is this &(*ptr).type the thing you're trying to do? Maybe &((*ptr).type) ?
ptr->member is like access to structure variable right? Also same for scanf() usr &ptr->member to get value. For char input use only ptr->charmember .
First let's do it the hard way. We'll assume that the code is already written, the compiler tells us nothing useful, and we don't have a debugger. First we put in some diagnostic output statements, and we discover that the crash happens in printContents:
printf("testing four\n"); /* we see this, so the program gets this far */
printf("Filename %s Size %d Type[%s] Accessed # %d \n", (*iptr).name, (*iptr).size, (*iptr).type, (*iptr).stamp);
printf("testing five\n"); /* the program crashes before this */
If we still can't see the bug, we narrow the problem down by preparing a minimal compete example. (This is a very valuable skill.) We compile and run the code over and over, commenting things out. When we comment something out and the code still segfaults, we remove it entirely; but if commenting it out makes the problem go away, we put it back in. Eventually we get down to a minimal case:
#include <stdio.h>
int main(void)
{
char type;
type = 'a';
printf("Type[%s]\n", type);
}
Now it should be obvious: when we printf("%s", x) something, printf expects x to be a string. That is, x should be a pointer to (i.e. the address of) the first element of a character array which ends with a null character. Instead we've given it a character (in this case 'a'), which it interprets as a number (in this case 97), and it tries to go to that address in memory and start reading; we're lucky to get nothing worse than a segfault. The fix is easy: decide whether type should be a char or a char[], if it's char then change the printf statement to "%c", if it's char[] then change its declaration.
Now an easy way. If we're using a good compiler like gcc, it will warn us that we're doing something fishy:
gcc foo.c -o foo
foo.c:35: warning: format ‘%s’ expects type ‘char *’, but argument 4 has type ‘int’
In future, there's a way you can save yourself all this trouble. Instead of writing a lot of code, getting a mysterious bug and backtracking, you can write in small increments. If you had added one term to that printf statement at a time, you would have seen exactly when the bug appeared, and which term was to blame.
Remember: start small and simple, add complexity a little at a time, test at every step, and never add to code that doesn't work.

Resources