c - FILE 结构在操作系统和体系结构之间是否一致?
问题描述
对于以下 C 代码片段,LLVM 将生成下面的 IR。
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("Hello world\n");
fflush(NULL);
return 0;
}
; ModuleID = 'a.c'
source_filename = "a.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"
%struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 }
%struct.__sFILEX = type opaque
%struct.__sbuf = type { i8*, i32 }
@str = private unnamed_addr constant [12 x i8] c"Hello world\00", align 1
; Function Attrs: nounwind ssp uwtable
define i32 @main() local_unnamed_addr #0 {
%1 = tail call i32 @puts(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @str, i64 0, i64 0))
%2 = tail call i32 @fflush(%struct.__sFILE* null)
ret i32 0
}
; Function Attrs: nounwind
declare i32 @fflush(%struct.__sFILE* nocapture) local_unnamed_addr #1
; Function Attrs: nounwind
declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #2
attributes #0 = { nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "darwin-stkchk-strong-link" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "darwin-stkchk-strong-link" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 2, !"SDK Version", [3 x i32] [i32 10, i32 15, i32 4]}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 7, !"PIC Level", i32 2}
!3 = !{!"Apple clang version 11.0.3 (clang-1103.0.32.59)"}
我可以认为相应 FILE 结构的结构声明在不同操作系统之间是一致的吗?有没有一种编程方式来获取这个结构的 LLVM 表示?
解决方案
FILE *
作为用户和操作系统之间的变量,后面的类型结构对您来说是不透明的。
更正式地说,它取决于您使用的 C(或 C++)编译器和支持库,但这通常是每个硬件和操作系统组合一个库,除了可能同时支持 32 位和 64 位的系统位代码。
一些程序 (Perl) 准备在配置阶段在不同机器上的结构内部进行探索,但它们这样做是在内部知识的情况下进行的。没有标准结构,除非像 GNU C 库这样的库可以跨机器对其进行标准化。但是假设它在任何地方都不一样是最安全的。
为了反驳Asadefa在他们的回答中提出的乐观观点,下面是 AIX 7.2 中的结构定义:
#if defined(__64BIT__) || defined(__ia64)
typedef struct {
unsigned char *_ptr;
unsigned char *_base;
unsigned char *_bufendp;
char *__newbase;
void *_lock;
int _cnt;
int _file;
int __stdioid;
short _flag;
short _unused;
long _unused1[4];
} FILE;
#else /* 32-bit POWER */
typedef struct {
unsigned char *_ptr;
int _cnt;
unsigned char *_base;
unsigned char *_bufendp;
short _flag;
short _file;
int __stdioid;
char *__newbase;
void *_lock;
} FILE;
#endif /* __64BIT__ || __ia64 */
这在单个操作系统上的 32 位和 64 位之间有所不同,并且与 Linux 和 macOS 上的结构完全无关。
Solaris 10 上的结构再次不同——使用了一些其他的不使用的位域:
struct __FILE_TAG /* needs to be binary-compatible with old versions */
{
#ifdef _STDIO_REVERSE
unsigned char *_ptr; /* next character from/to here in buffer */
int _cnt; /* number of available characters in buffer */
#else
int _cnt; /* number of available characters in buffer */
unsigned char *_ptr; /* next character from/to here in buffer */
#endif
unsigned char *_base; /* the buffer */
unsigned char _flag; /* the state of the stream */
unsigned char _file; /* Old home of the file descriptor */
/* Only fileno(3C) can retrieve the value now */
unsigned __orientation:2; /* the orientation of the stream */
unsigned __ionolock:1; /* turn off implicit locking */
unsigned __seekable:1; /* is file seekable? */
unsigned __extendedfd:1; /* enable extended FILE */
unsigned __xf_nocheck:1; /* no extended FILE runtime check */
unsigned __filler:10;
};
而我在 HP-UX 11.31 上找到的版本又不一样了:
typedef struct {
int __cnt;
unsigned char *__ptr;
unsigned char *__base;
unsigned short __flag;
unsigned char __fileL; /* low byte of file desc */
unsigned char __fileH; /* high byte of file desc */
} FILE;
当然,如果您的雷达屏幕上没有 Solaris、HP-UX、AIX,您可能会得出不同的结论,但不同系统之间肯定存在巨大差异。
推荐阅读
- mathematical-optimization - 如何使用 SCIP 解决 SAT 问题?
- ios - 如何使用 UITableViewCell 中的委托方法在标签中设置计算?
- android - 引起:net.sqlcipher.database.SQLiteException: file is not a database: ,编译时:select count(*) from sqlite_master
- reactjs - 将参数传递到后台屏幕并在本机反应中设置状态
- linux - Nexus 服务立即停止 2
- reactjs - 如何根据git分支更改变量值?
- azure-devops - VS403363:您的个人帐户无权访问此内容。Azure 开发运维
- python - 使用 HDBSCAN 的可调用指标*
- java - 使用字符串而不是使用单个字符的二叉搜索树高度
- python - 在 Robot Framework 的 websocketclient 库中传递子协议