Tag: 标准

sizeof(size_t)== sizeof(void *)总是如此吗?

C99 / C ++ 11标准是否保证sizeof(size_t) == sizeof(void*)始终为真? size_t f(void* p) { return (size_t)(p); // Is it safe? } void* f(size_t n) { return (void*)(n); // Is it safe? }

UINT_MAX + 1等于什么?

对于UINT_MAX + 1u ,C中定义的行为是什么? 假设它为零是多么安全?

为什么pow(-infinity,正非整数)+无限?

C99附件F(IEEE浮点支持)说: 对于y> 0而言, pow(−∞, y)返回+∞而不是奇数。 但是,比方说,( – ∞) 0.5实际上有虚数值±∞i,而不是+∞。 C99自己的sqrt(−∞)返回NaN并按预期生成域错误。 那么为什么需要返回+∞? (大多数其他语言直接使用C库,或者像本例中的Python一样,通过标准复制它所需的行为,因此在实践中这不仅仅影响C99。)

C中的常量数组类型,标准缺陷?

C99规范第6.7.3.8段规定 如果数组类型的规范包括任何类型限定符,则元素类型是合格的,而不是数组类型。 如果函数类型的规范包括任何类型的限定符,则行为未定义。 在基本原理 (逻辑页面87,物理页面94)中,给出了将平面指针投射到(可变长度)数组指针的示例。 void g(double *ap, int n) { double (*a)[n] = (double (*)[n]) ap; /* … */ a[1][2] /* … */ } 当然,如果数组ap未在函数内修改,则应将其标记为const,但是应该标记为 void g(const double *ap, int n) { const double (*a)[n] = (const double (*)[n]) ap; /* … */ } 不保留const限定符,因为(每6.7.3.8)它适用于目标的元素而不是目标本身,它具有数组类型double[n] 。 这意味着如果给出适当的标志( -Wcast-qual for GCC),编译器会正确地抱怨。 没有办法在C中表示const数组类型,但这种强制转换非常有用并且“正确”。 -Wcast-qual标志对于识别数组参数的误用非常有用,但误报不鼓励使用它。 请注意,索引a[i][j]更具可读性,并且对于许多编译器而言,产生的机器代码比ap[i*n+j]更好,因为前者允许从内循环中提取一些整数算术,而分析更少。 编译器是否应将此视为一种特殊情况,有效地将限定符从元素提升到数组类型以确定给定的强制转换是否删除限定符或是否应修改规范? […]

使用stddef.h的offsetof而不是滚动你自己的可移植性

这是一个挑剔的细节问题,有三个部分。 上下文是我希望说服一些人无条件地使用的offsetof定义而不是(在某些情况下)滚动自己的定义是安全的。 有问题的程序完全用普通的旧C编写,所以在回答时请完全忽略C ++ 。 第1部分:当以与标准offsetof相同的方式使用时,此宏的扩展是否会引发每个C89的未定义行为,为什么或为什么不这样,并且它在C99中是不同的? #define offset_of(tp, member) (((char*) &((tp*)0)->member) – (char*)0) 注意:人们感兴趣的所有实现都取代了标准的规则,指针只有在指向同一个数组时才能相互减去,通过定义所有指针,无论类型或值,指向单个指针全球地址空间。 因此,在争论这个宏的扩张引发未定义的行为时,请不要依赖于该规则。 第2部分:据您所知,有没有一个已发布的生产C实现,当进行上述宏的扩展时,(在某些情况下)将表现出与使用其offsetof宏时的行为不同的行为代替? 第3部分:据您所知,最近发布的生产C实现是什么,它没有提供stddef.h或者没有在该头文件中提供offsetof的工作定义? 该实现是否声称符合任何版本的C标准? 对于第2部分和第3部分,请仅在您可以命名特定实现并给出其发布日期时回答。 说明可能符合条件的实现的一般特征的答案对我没用。

为什么变量不能在C中的2个文件中定义两次

为什么我不能拥有一个; 在2个C文件中。 我打算将两者结合起来制作可执行文件。 我从经验中知道我不能,但我想找到标准C99所说的位置并密封我的理解。 我正在阅读http://www.open-std.org/jtc1/sc22/wg…docs/n1256.pdf中的 ISO C99标准。 它在第42页说: 6.2.2识别者的联系 1可以通过一个称为连接的过程,在不同的范围或相同的范围内多次声明一个标识符。通过一个名为linkage的过程来引用同一个对象或函数。有三种连接:外部,内部和无。 2在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或function。 在一个翻译单元内,具有内部链接的标识符的每个声明表示相同的对象或function。 没有链接的标识符的每个声明表示一个唯一的实体。 3如果对象或函数的文件范围标识声明包含存储类指定静态,则标识符具有内部链接。 4对于在存储类规范外部声明的标识符,在该范围内可以看到该标识符的先前声明,如果先前声明指定内部或外部链接,则后面声明中标识符的链接与在先前声明中指定的联系。 如果没有先前的声明可见,或者如果先前的声明没有指定链接,则标识符具有外部链接。 5如果函数的标识符声明没有存储类指定符,则其链接的确定就像是使用存储类指定符extern声明的。如果对象的标识符声明具有文件范围且没有存储空间 – 特定的,它的联系是外在的。 看完之后看起来如果我声明一个变量就像说int a; 在2个源文件中。 然后根据规则5和4都有外部链接,然后根据规则2,两者都应该引用同一个对象。 那为什么编译器会产生问题。 在标准中,暗示我们不能在2个源文件中声明这样,这应该抛出编译错误。 首先,在标准中,它表示int a是一个定义,然后它表示2个定义实例是不可接受的。 我知道这是不允许的,但是如果我能在标准中找到并密封我的理解,这对我来说非常有用。 请将以下标准的摘录与此规则相结合? 或者我错过了胶水? : 声明规定了一组标识符的解释和属性。 标识符的定义是对该标识符的声明: – 对于一个对象,导致为该对象保留存储; – 用于function,包括function体; – 对于枚举常量或typedef名称,是标识符的(唯一)声明。 正如5.1.1.1中所讨论的,预处理后的程序文本单元是一个翻译单元,它由一系列外部声明组成。 这些被描述为“外部”,因为它们出现在任何function之外(因此具有文件范围)。 正如6.7中所讨论的那样,一个声明也会导致为对象或由标识符命名的函数保留存储,这是一个定义。 外部定义是外部声明,它也是函数(除了内联定义)或对象的定义。 如果在表达式中使用了使用外部链接声明的标识符(除了作为sizeof运算符的操作数的一部分,其结果是整数常量),整个程序中的某个地方应该只有一个外部定义用于标识符; 否则,不得超过一个。 谢谢。

可以在便携式C中写入从double到int的转换

我需要编写像double_to_int(double val, int *err)这样的函数double_to_int(double val, int *err)它会在可能的情况下将double val转换为整数; 否则报告错误(NAN / INFs / OUT_OF_RANGE)。 所以伪代码实现看起来像: if isnan(val): err = ERR_NAN return 0 if val < MAX_INT: err = ERR_MINUS_INF return MIN_INT if … return (int)val 在SO上至少有两个类似的问题:在这个答案中它以足够干净的方式解决了,虽然它是C ++解决方案 – 在C中我们没有signed int的可移植数字。 在这个答案中,它解释了为什么我们不能只检查(val > INT_MAX || val < INT_MIN) 。 所以我看到的唯一可能的清洁方式是使用浮点环境,但它被称为实现定义的function。 所以我的问题是: 有没有办法以跨平台的方式实现double_to_intfunction(仅基于C标准,甚至不考虑支持IEEE-754的目标平台)。

严格的别名和内存位置

严格别名会阻止我们使用不兼容的类型访问相同的内存位置。 int* i = malloc( sizeof( int ) ) ; //assuming sizeof( int ) >= sizeof( float ) *i = 123 ; float* f = ( float* )i ; *f = 3.14f ; 根据C标准,这将是非法的,因为编译器“知道” float左值不能访问int 。 如果我使用该指针指向正确的内存,如下所示: int* i = malloc( sizeof( int ) + sizeof( float ) + MAX_PAD ) ; *i = 456 […]

标准是否定义空指针常量以将所有位设置为零?

(我引用的是ISO / IEC 9899:201x) 在这里我们看到,整数常量表达式有一个整数类型: 6.6常量表达式 6. 整数常量表达式应具有整数类型,并且只能具有整数常量的操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,_Alignof表达式以及作为强制转换的直接操作数的浮点常量。 整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof或_Alignof运算符的操作数的一部分。 这适用于任何整数类型: 6.2.6.2整数类型 5.未指定任何填充位的值。符号位为零的有符号整数类型的有效(非陷阱)对象表示是相应无符号类型的有效对象表示,并且应表示相同的值。 对于任何整数类型,所有位为零的对象表示应该是该类型中零值的表示。 然后我们看到使用值为0的整数常量表达式定义空指针常量。 6.3.2.3指针 3. 值为0的整型常量表达式,或者类型为void *的表达式,称为空指针常量。 如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较。 因此,空指针常量必须将其所有位设置为零。 但是在线和StackOverflow上有许多答案说这不是真的。 考虑到引用的部分,我很难相信他们。 (请使用最新标准的参考答案)

为什么编译器在尝试修改char *字符串文字时没有检测到并产生错误?

假设以下两段代码: char *c = “hello world”; c[1] = ‘y’; 上面的那个不起作用。 char c[] = “hello world”; c[1] = ‘y’; 这一个。 关于第一个,我理解字符串“hello world”可能存储在只读存储器部分中,因此无法更改。 然而,第二个在堆栈上创建一个字符数组,因此可以进行修改。 我的问题是 – 为什么编译器不会检测到第一类错误? 为什么不是C标准的一部分? 这有什么特别的原因吗?