Activity
не полностью инициализирован и готов к просмотру представлений до тех пор, пока onCreate()
не будет вызван в onCreate()
.
Объявляйте только следующие поля:
private EditText usernameField, passwordField;
private TextView error;
private ProgressBar progress;
] , а затем назначьте значения в onCreate
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
usernameField = (EditText)findViewById(R.id.username);
passwordField = (EditText)findViewById(R.id.password);
error = (TextView)findViewById(R.id.error);
progress = (ProgressBar)findViewById(R.id.progress);
}
Не может быть частью проблемы, но в качестве дополнительной рекомендации, Timer
запускает TimerTask
на фоне нить, и этого следует избегать в этом случае. Вместо этого замените Timer
на Handler
, чтобы запустить его в потоке пользовательского интерфейса.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}, 1500);
Это полностью зависит от компилятора. Помимо этого, некоторые переменные процедуры никогда не могут быть помещены в стек вообще, так как они могут провести всю свою жизнь в регистре.
Стандарт C не определяет какой-либо макет для других автоматических переменных. В частности, он специально говорит, что для избежания сомнений,
[...] Макет хранилища для параметров [function] не указан. (C11 6.9.1p9)
Из этого можно понять, что его расположение хранилища для любых других объектов также неуказано, за исключением нескольких требований которые заданы стандартом, в том числе, что нулевой указатель не может указывать на какой-либо действительный объект или функцию и макеты в совокупных объектах.
В стандарте C не содержится упоминания single слово «стек»; вполне возможно сделать, например, реализацию C, которая не содержит стеков, выделяя каждую запись активации из кучи (хотя тогда их можно было бы понять, чтобы сформировать стек).
Одной из причин дать компилятору некоторую свободу действий является эффективность. Однако текущие компиляторы также использовали бы это для обеспечения безопасности, используя трюки, такие как рандомизация размещения адресного пространства и канальные каналы , чтобы попытаться затруднить использование неопределенного поведения . Переупорядочение буферов сделано для более эффективного использования канарейки.
Итак, я сделал еще несколько экспериментов, и вот что я нашел. Кажется, он основан на том, является ли каждая переменная массивом. Учитывая этот вход:
void f5() {
int w;
int x[1];
int *ret;
int y;
int z[1];
}
В итоге я получаю это в gdb:
(gdb) p &w
$1 = (int *) 0xbffff4c4
(gdb) p &x
$2 = (int (*)[1]) 0xbffff4c0
(gdb) p &ret
$3 = (int **) 0xbffff4c8
(gdb) p &y
$4 = (int *) 0xbffff4cc
(gdb) p &z
$5 = (int (*)[1]) 0xbffff4bc
В этом случае int
s и указатели обрабатываются сначала, последним объявленным в верхнюю часть стека и сначала объявили ближе к основанию. Затем массивы обрабатываются в противоположном направлении, чем раньше декларация, самая высокая в стеке. Я уверен, что для этого есть веская причина. Интересно, что это.
Интересно, если вы добавите дополнительный int * ret2 в function1, тогда в моей системе порядок будет правильным, тогда как его вывести из строя только для трех локальных переменных. Я предполагаю, что это упорядочено таким образом из-за отражения стратегии распределения регистров, которая будет использоваться. Либо это, либо это произвольно.
Я понятия не имею , почему GCC организует свой стек так, как он делает (хотя, я думаю, вы можете взломать его источник или эту статью и узнать), но Я могу рассказать вам, как гарантировать порядок определенных переменных стека, если по какой-то причине вам нужно это сделать. Просто поставьте их в struct:
void function1() {
struct {
int x;
int y;
int z;
int *ret;
} locals;
}
Если моя память правильно меня обслуживает, spec гарантирует, что &ret > &z > &y > &x
. Я оставил свой K & amp; R на работе, поэтому я не могу приводить главу и стихи.
Обычно это связано с проблемами выравнивания.
Большинство процессоров медленнее извлекают данные, которые не выравниваются по процессорному слову.
Вероятно, что происходит, это то, что все объекты, которые больше или равны оптимальному выравниванию процессора вместе, а затем более плотно упаковывают вещи, которые не могут быть выровнены. Так получилось, что в вашем примере все ваши char
массивы имеют 4 байта, но я уверен, что если вы сделаете их 3 байта, они все равно окажутся в тех же местах.
Но если вы было четыре однобайтных массива, они могут оказаться в одном 4-байтовом диапазоне или выровнены в четырех отдельных.
Это все о том, что проще (переводится как «самый быстрый») для захвата процессора.
Это также может быть проблема безопасности?
int main()
{
int array[10];
int i;
for (i = 0; i <= 10; ++i)
{
array[i] = 0;
}
}
Если массив меньше в стеке, чем i, этот код будет циклически бесконечно (потому что он ошибочно обращается к нулевому массиву [10], что я). Помещая массив выше в стеке, попытки доступа к памяти за пределами стека будут чаще касаться нераспределенной памяти и сбой, а не вызывать неопределенное поведение.
Я экспериментировал с этим же кодом один раз с gcc и не смог выполнить его, за исключением конкретной комбинации флагов, которые я не помню сейчас. В любом случае он разместил массив несколько байтов от i.
Я предполагаю, что это связано с тем, как данные загружаются в регистры. Возможно, с массивами char, компилятор работает с некоторой магией, чтобы делать что-то параллельно, и это имеет какое-то отношение к положению в памяти, чтобы легко загружать данные в регистры. Попробуйте выполнить компиляцию с различными уровнями оптимизации и попробуйте использовать int buffer1[1]
.
Не только ISO C ничего не говорит о упорядочении локальных переменных в стеке, он даже не гарантирует, что стек даже существует. Стандарт просто говорит о масштабах и времени жизни переменных внутри блока.