I'm trying to port some code from windows to linux, but I'm having difficulty with support for large files. off_t seems to be defined when gcc is run with -std=c89 but not for -std=c99. Even a trivial test case will not compile:
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
int main()
{
off_t x = 0;
return 0;
}
It really doesn't seem like this should be difficult (in fact, it's not on all other operating systems). Anyone have any idea what is happening?
The type off_t is not defined by ISO C; it's defined by POSIX.
I get
error: unknown type name ‘off_t’
if I compile with either -std=c90, -std=c99, or -std=c11. That's to be expected, since those options specify conformance to the relevant C standard. Since you're compiling C code that doesn't conform to any of those C standards, you shouldn't use those options.
I find that off_t is defined if I compile with -std=gnu90, -std=gnu99, or -std=gnu11.
Also, off_t is the return type of the lseek function, whose man page on my system says it requires:
#include <sys/types.h>
#include <unistd.h>
You should add those.
Related
This is my code:
#include <stdio.h>
#include <sys/statfs.h>
int main(int argc, char** argv)
{
struct statfs64 mystatfs64;
statfs64("/", &mystatfs64);
return 0;
}
But I get this error:
error: storage size of ‘mystatfs64’ isn’t known
warning: implicit declaration of function ‘statfs64’; did you mean ‘statfs’?
On the man page it says: The glibc statfs() and fstatfs() wrapper functions transparently deal with the kernel differences.
So I changed my code to:
#include <stdio.h>
#include <sys/statfs.h>
int main(int argc, char** argv)
{
struct statfs mystatfs;
statfs("/", &mystatfs);
return 0;
}
It now compiles but sizeof(((struct statfs*)0)->f_blocks) is 4 so I can't handle big file systems.
I also tried to define __USE_LARGEFILE64 and __USE_FILE_OFFSET64 without any success.
The __USE_* macros are for glibc's internal header features.h to define, not you. If you try to define them yourself, they won't work.
You are instead supposed to define macros from a different set, called the "feature test macros" or "feature selection macros" and partially specified by POSIX. The most up-to-date and coherent documentation of the full set of feature test macros understood by glibc is in the Linux manpages: feature_test_macros(7). Note that most of these macros must be defined before you include any system headers.
The best way to write the code you're trying to write is to use the _FILE_OFFSET_BITS feature test macro to make normal off_t, fsblkcnt_t, etc. be 64 bits wide:
#define _FILE_OFFSET_BITS 64
#include <inttypes.h>
#include <stdio.h>
#include <sys/statfs.h>
int main(int argc, char** argv)
{
struct statfs mystatfs;
statfs("/", &mystatfs);
printf("block count: %"PRIu64"\n", mystatfs.f_blocks);
return 0;
}
If you don't want to add this #define to the top of every .c file of your program, you may instead be able to add -D_FILE_OFFSET_BITS=64 to your compilation options in your Makefile or equivalent (for instance, add it to CPPFLAGS if you're using for Make's standard built-in compilation rules).
You also have the option of using _LARGEFILE64_SOURCE to gain access to the xxx64 functions and types, but this is discouraged by the C library maintainers: note what it says about it in the manpage I linked above
_LARGEFILE64_SOURCEExpose definitions for the alternative API specified by the LFS (Large File Summit) as a "transitional extension" to the Single UNIX Specification. (See ⟨https://www.opengroup.org/platform/lfs.html⟩.) The alternative API consists of a set of new objects (i.e., functions and types) whose names are suffixed with "64" (e.g., off64_t versus off_t, lseek64() versus lseek(), etc.). New programs should not employ this macro; instead _FILE_OFFSET_BITS=64 should be employed.
(boldface: my emphasis)
Here is my dead simple dummy code:
#include <errno.h>
int main(void)
{
errno_t e;
return 0;
}
Which surprisingly raises this error:
main.c:5:5: error: use of undeclared identifier 'errno_t'
errno_t x;
^
I started to follow the traces: when the compiler sees the <...> inclusions it will first look at /usr/include where of course I found errno.h file. Actually it has a single line in it, besides the license comment, which is:
#include <sys/errno.h>
Now, at /usr/include/sys in errno.h I found the following lines:
#include <sys/cdefs.h>
#if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1
#include <sys/_types/_errno_t.h>
#endif
And at /usr/include/_types in _errno_t.h I found this:
typedef int errno_t;
So it looks like, it is there, and it is an alias of the integer type, and part of the errno.h -- just as it should be.
Then why isn't it included? Why the compiler raises the undeclared identifier error?
Thanks in advance!
RELEVANT INFO:
Compiler:
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)`
Compiler flags:
-std=c11 -I/usr/include/sys -I/usr/local/include
The macro variable __STDC_WANT_LIB_EXT1__ will be defined at /usr/include/sys in cdefs.h in the following lines:
/* If the developer has neither requested a strict language mode nor a version
* of POSIX, turn on functionality provided by __STDC_WANT_LIB_EXT1__ as part
* of __DARWIN_C_FULL.
*/
#if !defined(__STDC_WANT_LIB_EXT1__) && !defined(__STRICT_ANSI__) && __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#define __STDC_WANT_LIB_EXT1__ 1
#endif
UPDATE:
As #PaulR said in the comment section: if I remove the -std=c11 flag, it compiles. Which is just as surprising as the error raised if the flag was included. So I extend this question with a sub-question:
Is not errno_t part of the C11 standard, or why isn't it included, when the standard is specified for the compiler?
errno_t is not a standard type; it's part of the optional (and widely disliked and unsupported) Annex K, included with ISO C11 only because of one particular vendor with a history of ignoring and sabotaging the standard.
Since Annex K defines errno_t as int, the type of the errno object is int, and all error codes are int, simply use int in your programs. It's much more portable than relying on an optional feature which is unlikely to be supported.
When I compile the following program (the code for all the defines I've gotten from 64 bit ntohl() in C++? which seemed sensible):
#include <stdint.h>
#if defined(__linux__)
#include <endian.h> //htobe64,be64toh
#include <arpa/inet.h> //ntohs, ntohl, htonl, htons
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h>
#elif defined(__OpenBSD__)
#include <sys/types.h>
#define be16toh(x) betoh16(x)
#define be32toh(x) betoh32(x)
#define be64toh(x) betoh64(x)
#endif
int main()
{
int64_t i = 0x1212121234343434;
int64_t j = be64toh(i);
return 0;
}
I get a linking error when compiling it with the following command (I'm running linux):
gcc -std=c99 endian_test.c -o endian
The error i receive is:
user#host ~/src/c $ gcc -std=c99 derp.c
endian_test.c: In function ‘main’:
endian_test.c:17:2: warning: implicit declaration of function ‘be64toh’ [-Wimplicit-function-declaration]
int64_t j = be64toh(i);
^
/tmp/ccYonfH4.o: In function `main':
endian_test.c:(.text+0x23): undefined reference to `be64toh'
collect2: error: ld returned 1 exit status
Which to me indicates two things, the header itself is included but doesn't really contain the functions/macros needed for this to work and because that means the compiler hopes it's gonna find the function later it tries to go ahead anyway but fails when trying to link.
But if i use the following command to compile (just remove -std=c99):
gcc endian_test.c -o endian
Everything is smooth as butter and works. Any idea why it's happening and what i could do to remedy it? To me it doesn't make sense that functions given by the kernel (or am i mistaken in that fact?) change depending on what standard i use when compiling?
Thanks in advance!
Without explicit -std= option, calling gcc is the same as -std=gnu89 with means C89 + GNU extensions. The GNU extensions will enable macros which will enable the presence of the functions in your header.
If you see the be64toh manual, you will see that it needs the _BSD_SOURCE to be defined. So on Linux #define it before you include <endian.h>.
I had this problem. The solution was to declare not only
#define _BSD_SOURCE
but also
#define __USE_BSD
https://github.com/tailhook/zerogw/pull/34/files#r32008569
Recent changes to glibc has meant you need
#define _DEFAULT_SOURCE
instead of
#define _BSD_SOURCE
Deprecation of _BSD_SOURCE and _SVID_SOURCE feature macros
I'm writing a program for my study and therefore I have to descripe a few wars to get the limits of some data types.
When I'm writing this:
#include <limits.h>
#include <stdio.h>
int main(void)
{
printf("%d\n", CHAR_BIT);
printf("%d\n", LONG_BIT);
return 0;
}
but it gives me the following error:
a.c: In function ‘main’:
a.c:7:17: error: ‘LONG_BIT’ undeclared (first use in this function)
printf("%d\n", LONG_BIT);
^
a.c:7:17: note: each undeclared identifier is reported only once for each function it appears in
even gcc -E gives me this
int main(void)
{
printf("%d\n", 8);
printf("%d\n", LONG_BIT);
return 0;
}
But a grep in limits.h doesn't give me the answer. But bits/xopen_lim.h has this declaration and it should be included when
__USE_XOPEN
is declared, but even a manual declaration won't give me a result.
So where is the problem? A look in the manpage says there is a LONG_BIT macro but gcc says no.
gcc version 4.8.0 (GCC)
OS arch
[edit]
For those who say LONG_BIT is not a c-standard, type
man 0 limits.h
and search for LONG_BIT. For me there are two entries under Numerical Limits and therefore I think LONG_BIT exist.
And no, including bits/xopen_lim.h is not realy an option, because it should be included by limits.h and not manually
Your issue is that you shouldn't be defining __USE_XOPEN. If you take a look at /usr/include/features.h you will see it explicitly undefines it and then redefines these macros based on feature test macros. You probably want to define _XOPEN_SOURCE instead, something like:
gcc -D_XOPEN_SOURCE=700 -o longbit longbit.c
From features.h:
_XOPEN_SOURCE Includes POSIX and XPG things. Set to 500 if
Single Unix conformance is wanted, to 600 for the
sixth revision, to 700 for the seventh revision.
_XOPEN_SOURCE_EXTENDED XPG things and X/Open Unix
extensions.
Also, wrt directly including xopen_lim.h:
/*
* Never include this file directly; use <limits.h> instead.
*/
So, I wouldn't recommend directly including it. Also, see man feature_test_macros or info '(libc)Feature Test Macros'.
LONG_BIT is not a thing in standard C.
For a portable approach, just do this:
CHAR_BIT * sizeof(long)
http://www.cplusplus.com/reference/climits/
There is nothing as such LONG_BIT in limits.h
Consider the following C code:
#include <stdio.h>
#include <stdlib.h>
void fatal(const char* message){
/*
Prints a message and terminates the program.
Closes all open i/o streams before exiting.
*/
printf("%s\n", message);
fcloseall();
exit(EXIT_FAILURE);
}
I'm using clang 2.8 to compile: clang -Wall -std=gnu99 -o <executable> <source.c>
And get: implicit declaration of function 'fcloseall' is invalid in C99
Which is true, but i'm explicitly compiling to gnu99 [which should support fcloseall()], and not to c99.
Although the code runs, I don't like to have unresolved warnings when compiling.
How can i solve this?
Edit: corrected tipo.
To include non-standard extensions when you include standard headers you need to define the appropriate feature test macro. In this case _GNU_SOURCE should work.
#define _GNU_SOURCE
#include <stdio.h>
This is independent of -std=gnu99 which enables language extensions, not library extensions.
Here in the man page of fcloseall()
#define _GNU_SOURCE
#include <stdio.h>
You have to define macros _GNU_SOURCE is you snippet, along with stdio.h header. _GNU_SOURCE is a feature test macros which is used to create portable application.