初始化程序不是常数......我知道,但我觉得这应该有用,为什么不呢

时间:2016-12-07 23:24:09

标签: c gcc

如果删除静态限定符,以下代码编译正常,但我不明白为什么它不起作用。我可以在.rodata部分看到字符串(在没有静态限定符的情况下进行编译时),最终的程序集只是在调用printf之前适当地加载指针。

#include <stdio.h>
#define S "Testing"
#define C 't'
typedef struct {
    char const * const s;
    char const c;
} foo;
int main(int argc, char **argv)
{
    static foo const f = {
        .s = S,
        .c = S[3],
    };
    printf("s = %s, c = %c\n", f.s, f.c);
    return 0;
}

此外,如果我使用:

,它可以使用静态限定符进行编译
.c = C,

有趣的是,程序集看起来完全相同(是的,gcc从“测试”中劫持't')

这个片段只是为了演示我在一个更复杂的问题中遇到的具体例子。为什么编译器不能将字符串文字[]元素视为常量,当它明确的时候呢?

BTW,使用gcc 5.4编译,只有-O2

编辑:澄清一下,问题是f.c初始化

编辑:感谢大家的见解。总之,预处理器不能对字符串做任何事情,这是蹩脚的。如果我实际实现了我在函数范围内尝试做的事情,编译器(带优化)最终会将所有内容处理到.rodata部分中的常量,但不幸的是我无法在全局范围内完成相同的操作

解决方案:编写自定义python脚本(或任何您喜欢的脚本语言)来生成代码,或使用c ++

4 个答案:

答案 0 :(得分:4)

在C语言中,具有静态存储持续时间的对象需要常量表达式作为初始化程序。 S[3]不是C中的常量表达式。基本上不允许在常量表达式中“从内存中读取”,即不允许使用一元*运算符,因此不允许使用[]运算符来读取数组元素。

与此同时,'t'立即成为常量,这就是为什么在用S[3]替换C时代码会编译。

答案 1 :(得分:2)

从C11 6.7.9 / 4(初始化 - 约束):

  

具有静态或线程存储持续时间的对象的初始值设定项中的所有表达式都应为常量表达式或字符串文字。

常量表达式的定义见6.6。特别是6.6 / 7:

  

初始值设定项中的常量表达式允许更多纬度。这样的常量表达式应为或评估为以下之一:

     
      
  • 算术常量表达式
  •   
  • 一个空指针常量,
  •   
  • 地址常量,或
  •   
  • 完整对象类型的地址常量加上或减去整数常量表达式。
  •   

然而S[3]不是那些。算术常量表达式只允许具有算术类型常量的操作数(简而言之),但S[3]表示*(S + 3)具有指针操作数。

使用't'作为初始化程序很好,这是一个字符常量,因此是一个算术常量表达式。

注意:常量表达式与&#34; const - 限定变量&#34;具有完全不同的含义。常量表达式永远不会const - 限定,并且是变量和对象的不相交集。

可能已经定义了语言,因此使用有效索引索引字符串文字会计为常量表达式,但它不是。

请注意,字符串文字不是常量表达式(尽管它们的地址是)。它们是非const char的数组。还有一个规则是修改字符串文字是未定义的行为。因此,可移植代码必须将字符串文字视为const,尽管从技术上讲它不是BoundedOutOfOrdernessTimestampExtractor。从历史上看,一些编译器允许修改字符串文字。

答案 2 :(得分:0)

我不确定您的最终目标是什么,但也许struct中的这一小变化可以提供帮助。根据标准:

  

数组下标 [] 和成员访问 - &gt;   运营商,地址&amp; 和间接 * 一元运营商,   和指针强制转换可用于创建地址常量,   但是使用这些物品不能获得物体的价值   运营商。
  ISO / IEC 9899:2011 6.6 / 9

在您的示例的代码中,您尝试在初始值设定项中使用S[3]的值作为常量表达式。上面说明了为什么这是不可能的,但您可以使用S[3]地址作为常量表达式:

#include <stdio.h>
#define S "Testing"
#define C 't'
typedef struct {
    char const * const s;
    char const * const c;
} foo;
int main(int argc, char **argv)
{
    static foo const f = {
        .s = S,
        .c = &S[3],
    };
    printf("s = %s, c = %c\n", f.s, *(f.c));
    return 0;
}

编译并运行此代码时,输​​出为:

s = Testing, c = t

答案 3 :(得分:-5)

你的问题是,define不会在预处理器中使用初始化。你需要:

.ui-pager-control>.ui-pg-table>tbody>tr>td>table.ui-pg-table {
    display: inline-block;
    top: .6em;
}
.ui-pager-control>.ui-pg-table>tbody>tr>td>.ui-paging-info {
    display: inline-block;
    float: right;
    margin-top: 1.2em;
}