I've been looking at other questions and none of the solutions have worked so I'll ask my own question.
I'm working on a linux VM and having trouble compiling my code, here are my includes, the error received by the compiler and the code its referring to:
Error:
linux.c:156:11: warning: implicit declaration of function 'scan_s' [-Wimplicit-function-declaration]
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "ctype.h"
scanf_s("%[^\n]s", filename, maxFilename);
scanf_s is part of the bounds-checking extension that your compiler may not support. Use #ifdef __STDC_LIB_EXT1__ to see if your library/implementation supports it -- if not, fall back to using something like
char fmt[16];
sprintf(fmt, "%%%d[^\n]", maxFilename);
scanf(fmt, maxFilename, filename);
or
fgets(filename, maxFilename, stdin);
if (char *p = strchr(filename, '\n')) *p = '\0';
instead.
Note that the s in the format string of your example is non-sensical and will not match anything (any s will be absorbed by the %[^\n] as it is not a newline.
As far as I know, only Microsoft compilers support this extension.
Related
I am a beginner and I am learning C and using Visual Studio Code 2019 and I get an error like this:
Exception thrown at 0x7C97E63C (ucrtbased.dll) in string.exe: 0xC0000005: Access violation writing location 0x00900000".
Here is my code:
#include <stdio.h>
int main() {
char str[50];
scanf_s("%s", &str);
printf("%s", str);
return 0;
}
I know it is a very noob type question but when I compile the same code with Code::Blocks, it runs fine but ultimately I have to use VScode to build projects so I am stuck here. How can I fix this problem?
Your code has undefined behavior because you do not pass the size argument scanf_s expects after the destination pointer for the %s conversion. Furthermore, you should pass str, not &str although that should not cause a problem. You should also test if scanf_s succeeds to avoid calling printf with an uninitialized array if it fails, for example if the input stream is an empty file.
Finally, there is a problem with scanf_s that is well beyond your current skill level: this function is defined with different semantics on Windows and in the C Standard, so the way you can pass the size argument depends on the compiler.
For standard complying compilers, such as gcc and clang in linux and Mac/OS, you would use sizeof str which has type size_t, but on Windows you must cast this as (unsigned) because Microsoft's version of scanf_s expects this type, which has a different size on 64-bit systems. For this and other reasons, scanf_s should not be used in a portable program.
Here is a modified version for linux and Mac/OS:
#include <stdio.h>
int main() {
char str[50];
if (scanf("%49s", str) == 1) {
printf("%s\n", str);
}
return 0;
}
Here is a modified version for Windows, where the compiler insists on the use of scanf_s with non-standard semantics:
#include <stdio.h>
int main() {
char str[50];
if (scanf_s("%49s", str, (unsigned)sizeof(str)) == 1) {
printf("%s\n", str);
}
return 0;
}
The 49 in %49s prevents scanf_s from triggering an implementation defined exception.
I am cleaning up warnings and found the following error:
warning: assignment makes pointer from integer without a cast buf = aligned_alloc(ALIGN_VALUE,BUF_SZ);
This call is at the very top of the function, essentially:
char* buf;
buf = aligned_alloc(ALIGN_VALUE,BUF_SZ);
It is my understanding that aligned_alloc returns a void *. If cast the return from aligned_alloc to a (char *) I get:
warning: cast to pointer from integer of different size [-Wint-to-pointer-ast] buf = (char*)aligned_alloc(ALIGN_VALUE,BUF_SZ);
The only thing that seems to fix it is
buf = (char*)(uintptr_t)aligned_alloc(ALIGN_VALUE,BUF_SZ);
I have made sure that I am including stdlib.h to avoid implicit declarations referred to in another post. I assumed the cast to char pointer should have resolved this. I am not understanding why the cast to uintptr_t resolves it when void* and uintptr_t are equivalent as far as I understand.
The following is an example of the structure of the file
#include <syslog.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <sys/ioctl.h>
#include <sys/mman.h> // mmap
#include <sys/time.h>
#include <unistd.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdio.h>
#include <pthread.h>
void* ax_read_thread(void* arg)
{
fprintf(stderr, "read thread started\n");
ax_priv* priv = (ax_priv*)arg;
char* buf;
uint32_t count = 0;
size_t len, transferred = 0;
buf = (char*)(uintptr_t)aligned_alloc(ALIGN_VALUE,BUF_SZ);
if (buf == NULL){
fprintf(stderr, "Aligned alloc failed\n");
pthread_exit(NULL);
}
while(1){
//do things
}
}
Thank you for all of the help. I see now that the warning is a result of not indicating the proper version when invoking the compiler.
This answer largely summarizes the observations and suggestions from the comments thread, including mine and many others', and wraps them in a bit of expository prose.
In the first place, the problem arises because when you build your program with your present toolchain, in its current form, the aligned_alloc() function is not explicitly declared. In the absence of a declaration, the compiler is inferring its signature: it guesses that the function returns int, and that its parameter types are those obtained via the default argument promotions applied to the types of the actual arguments. The compiler then warns you that those inferences -- especially the return type -- seem inconsistent with how you're actually using the function.
The solution, supposing that the function is available in your C library at all, is to ensure that a correct prototype is provided. You could insert the prototype manually, but you shouldn't. Since it's a standard library function, you should get its declaration from the appropriate header, which for this function is stdlib.h.
HOWEVER, this particular function is new in C11, and evidently you're using a version of GCC that defaults to compiling for an earlier standard. Glibc supports that in part by protecting functions that are new in C11 with a feature-test macro, _ISOC11_SOURCE. This is for your protection: in the event that you're building code written for an earlier standard, and that code happens to provide is own function with the same name as one of C11's new functions, the feature-test system prevents you from suffering a name collision.
If you are indeed writing for C11, as seems to be the case, and if your version of gcc has an option to support C11 (i.e. -std=c11 and/or -std=gnu11), then compiling with that option enabled is your best alternative. If you happen to have a version of Glibc that provides aligned_alloc() but not a version of the compiler that supports a C11 mode, then you have the alternative of manually ensuring that the needed feature test macro is defined to the compiler before any of the standard headers are included. You can do that via a #define at the top of your source file, or via a command-line option to the compiler (e.g. -D_ISOC11_SOURCE=1).
Glibc does have aligned_alloc() from at least version 2.17 (but I think from as early as 2.16). GCC does have a C11 mode since at least version 4.8. If your versions of these components are at least that recent, then it should be sufficient to add the option -std=c11 (to omit GNU extensions) or -std=gnu11 (to support GNU extensions) to your compilation command:
gcc -std=c11 my_program.c
I don't understand the below error message when I compile this code. I couldn't find out what wrong with it.
Description Resource Path Location
Type expected ‘)’ before ‘SCNu64’.
#include <inttypes.h>
int calc_rate(uint64_t *rate, char val[], char mult[]) {
int rc = sscanf(val, "%" SCNu64 "%2s", rate, mult);
}
If you have both <inttypes.h> and <stdio.h> included, then the code fragment shown compiles cleanly. (You can't call sscanf() legally unless there's a prototype in scope.) That means the problem is in the code prior to what you are showing. Or it means that your compiler doesn't provide support for exactly 64-bit types, which is rather unlikely unless you're on a relatively obscure mainframe, or you aren't compiling in C99 or C11 mode.
So I'm new to C and I'm playing around with functions in the GNU C Library when I come across https://www.gnu.org/software/libc/manual/html_node/strfry.html#strfry
Intrigued, I wrote a little tester program:
1 #include <stdio.h>
2 #include <string.h>
3
4 main ()
5 {
6 char *str = "test123abc";
7 char *other;
8
9 other = strfry(str);
10 printf("%s\n", other);
11 return 0;
12 }
gcc test.c outputs test.c:9: warning: assignment makes pointer from integer without a cast
Why?
/usr/include/string.h has the following entry:
extern char *strfry (char *__string) __THROW __nonnull ((1));
How can a char *function(...) return int?
Thanks
Since strfry is a GNU extension, you need to #define _GNU_SOURCE to use it. If you fail to provide that #define, the declaration will not be visible and the compiler will automatically assume that the function returns int.
A related problem, as pointed out by perreal, is that it is undefined behavior to modify a literal string. Once you make the declaration of strfry visible to the compiler, this will be duly reported.
Do note that the strfry function and its cousin memfrob are not entirely serious and are rarely used in production.
To have strfry available, you need
#define _GNU_SOURCE
otherwise the prototype is not exposed and the implicit declaration is assumed to return an int.
The problem is you don't have a prototype in scope for strfry() and the compiler assumes it returns an int. When it wants to assign that int to a char* it complains with the message you specify.
According to my man pages, you need to #define _GNU_SOURCE at the very top of your source code, especially before standard #includes
#define _GNU_SOURCE
/* rest of your program */
You can't modify a literal string:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
int main () {
char *str = "test123abc";
char other[256];
strcpy(other, str);
strfry(other);
printf("%s\n", other);
return 0;
}
Right now I am only trying to get my getline() function to work. I have the code from the book and it seems to be identical, but I cant get it to compile. This is homework but this part should be just copying from the book.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//error list
#define ENDOFFILE = -1;
#define TOOMANYNUMS = -2;
#define LIMIT = 256;
//functions declared
int get_line(char line[], int);
//main
main(){
char line[255];
int num[6];
printf("Please input numbers %c: ", line);
get_line(line,LIMIT);
}
//functions
int get_line(char s[],int lim){
int c, i;
for (i=0;i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if(c=='\n'){
s[i]=c;
++i;
}
s[i]='\0';
return i;
}
Now (edited at 10:22) I only get one error:
18 - expected expression before equal
conflicting types for 'getline'
getline might be a function in your standard library, e.g. thisone. If you want to reimplement it, give it a different name.
too few arguments to function 'getline'
You are calling getline() in main() without any arguments, but a few lines above you state that getline takes a char[] and an int. call it like getline(line,sizeof line);
Right now I am only trying to get my getline() function to work.
getline() is a name of Linux function, declared in the stdio.h. C compiler complains that there are two conflicting declarations.
Simply give your getline() function a different name.
Edit1: That:
#define ENDOFFILE = -1;
Should be
#define ENDOFFILE -1
No =, no ; needed for preprocessor directives.
The problem appears to be that the system you are compiling this on appears to have a getline() function already defined, and your definition is conflicting with that. It appears that glibc, the C library used on Linux, has a non-standard getline() function declared in stdio.h. It shouldn't be defined unless you include a line like #define _GNU_SOURCE to opt-in to including non-standard functions, but it may be that this is pre-defined based on how you are compiling your code.
The easiest solution would be to rename your function to something else, but you could also try and find in your compiler options why GNU extensions are being turned on.
Now that you've edited your code, your second problem is that your #define lines are wrong. You don't need an equal or semicolon; these are processed by the preprocessor, which has a different syntax than C, and all you need to do is write #define NAME VALUE.
The proper syntax would be:
#define ENDOFFILE -1
#define TOOMANYNUMS -2
#define LIMIT 256
you need to realize:
it is general an error to write
#define macro like what you wrote,because #define macro is
simply string replacement,so this
statement get_line(line,LIMIT) is
actually get_line(line,=256;)
processed by the compiler,then the
compiling error occurred. Just
change #define LIMIT =256; to
#define LIMIT 256 would be ok.
as is mentioned in the previous
replies,never write codes that
library provided,getline is a function defined in stdio.h.
hope this helps.